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

# In[1]:

from scipy.special import comb

# In[2]:

import math

# In[3]:

def ensemble_error(n_classifier, error):
    k_start = int(math.ceil(n_classifier / 2.))
    probs = [comb(n_classifier, k) *
            error**k *
            (1-error)**(n_classifier - k)
            for k in range(k_start, n_classifier +1)]
    return sum(probs)

# In[ ]:

# In[4]:

ensemble_error(n_classifier=11, error=0.25)

# In[5]:

import numpy as np

# In[6]:

import matplotlib.pyplot as plt

# In[7]:

error_range = np.arange(0.0, 1.01, 0.01)

# In[8]:

ens_errors = [ensemble_error(n_classifier=11, error=error)
             for error in error_range]

# In[9]:

plt.plot(error_range, ens_errors,
        label='Ensemble error',
        linewidth=2)
plt.plot(error_range, error_range,
        linestyle='--', label='Base error',
        linewidth=2)
plt.xlabel('Base error')
plt.ylabel('Base/Ensemble error')
plt.legend(loc='upper left')
plt.grid(alpha=0.5)
plt.show()

# In[10]:

import numpy as np

# In[11]:

np.argmax(np.bincount([0, 0, 1],
                     weights=[0.2, 0.2, 0.6]))

# In[12]:

ex = np.array([[0.9, 0.1],
              [0.8, 0.2],
              [0.4, 0.6]])

# In[13]:

p = np.average(ex, axis=0, weights=[0.2, 0.2, 0.6])

# In[14]:

p

# In[15]:

np.argmax(p)

# In[16]:

from sklearn.base import BaseEstimator

# In[17]:

from sklearn.base import ClassifierMixin

# In[18]:

from sklearn.preprocessing import LabelEncoder

# In[19]:

from sklearn.base import clone

# In[20]:

from sklearn.pipeline import _name_estimators

# In[21]:

import numpy as np

# In[22]:

import operator

# In[23]:

class MajorityVoteClassifier(BaseEstimator,
                             ClassifierMixin):
    """A majority vote ensemble classifier

    Parameters
    classifier : array-like, shape = [n_classifiers]
     Different classifiers for the ensemble

     vote : str, {'classlabel', 'probability'}
       Default: 'classlabel'
       If'classlabel' the prediciton is based on
       the argmax of class labels. Else if
       'probability', the argmax of the sum of
       probabilites is used to predict the class label
       (recommended for calibrated classifiers).

    weights : array-like, shape = [n_classifiers]
      Optional, default: None
      If a list of 'int' or 'float' values are
      provided, the classifiers are weighted by
      importance; Uses uniform weight if 'weights=None'.

      """
    def __init__(self, classifiers,
                vote='classlabel', weights=None):
        self.classifiers = classifiers
        self.named_classifiers = {key: value for
                                  key, value in
                                  _name_estimators(classifiers)}
        self.vote = vote
        self.weights = weights
    def fit(self, X, y):
        """Fit classifiers.

        Parameters
        X : {array-like, sparse matrix},
            shape = [n_examples, n_features]
            Matrix of training examples.

        y : array-like, shape = [n_examples]
            Vector of target class labels.

        Returns

        self : object

        """
        if self.vote not in ('probability', 'classlabel'):
            raise ValueError("vote must be 'probability'"
                            "or 'classlabel'; got (vote=%r)"
                            % self.vote)
        if self.weights and len(self.weights) != len(self.classifiers):
            raise ValueError("Number of classifier and weights"
                             "must be equal; got %d weights,"
                             "%d classifiers"
                             % (len(self.weights),
                             len(self.classifers)))
        self.lablenc_ = LabelEncoder()
        self.lablenc_.fit(y)
        self.classes_ = self.lablenc_.classes_
        self.classifiers_ = []
        for clf in self.classifiers:
            fitted_clf = clone(clf).fit(X, self.lablenc_.transform(y))
            self.classifiers_.append(fitted_clf)
        return self

    def predict(self, X):
            """Predict class labels for X.

            Parameters
            X : {array-like, sparse matrix},
                Shape = [n_examples, n_features]
                Matrix of training examples.

            Returns

            maj_vote : array-like, shape = [n_examples]
                Predicted class labels.

            """
            if self.vote == 'probability':
                maj_vote = np.argmax(self.predict_proba(X), axis=1)
            else: # 'classlabel' vote

                predictions = np.asarray([clf.predict(X)
                                         for clf in
                                         self.classifiers_]).T
                maj_vote = np.apply_along_axis(lambda x: np.argmax(
                                               np.bincount(x,
                                               weights=self.weights)),
                                               axis=1,
                                               arr=predictions)
                maj_vote = self.lablenc_.inverse_transform(maj_vote)
            return maj_vote

    def predict_proba(self, X):
            """ Predict class probabilities for X.

            Parameters
            X : {array-like, sparse matrix},
                shape = [n_examples, n_features]
                Training vectors, where
                n_examples is the number of examples and
                n_features is the number of features.

            Returns

          avg_proba : array-like,
                shape = [n_examples, n_classes]
                Weighted average probability for
                each class per example.

            """
            probas = np.asarray([clf.predict_proba(X)
                            for clf in self.classifiers_])
            avg_proba = np.average(probas, axis=0,
                                  weights=self.weights)
            return avg_proba

    def get_params(self, deep=True):
            """Get classifier parameter names for GridSearch"""
            if not deep:
                return super(MajorityVoteClassifier,
                            self).get_params(deep=False)
            else:
                out = self.named_classifiers.copy()
                for name, step in self.named_classifiers.items():
                    for key, value in step.get_params(
                            deep=True).items():
                        out['%s__%s' % (name, key)] = value
            return out

# In[24]:

from sklearn import datasets

# In[25]:

from sklearn.model_selection import train_test_split

# In[26]:

from sklearn.preprocessing import StandardScaler

# In[27]:

from sklearn.preprocessing import LabelEncoder

# In[28]:

iris = datasets.load_iris()

# In[29]:

X, y = iris.data[50:, [1, 2]], iris.target[50:]

# In[30]:

le = LabelEncoder()

# In[31]:

y = le.fit_transform(y)

# In[32]:

X_train, X_test, y_train, y_test =   train_test_split(X, y,
                   test_size=0.5,
                   random_state=1,
                   stratify=y)

# In[33]:

from sklearn.model_selection import cross_val_score

# In[34]:

from sklearn.linear_model import LogisticRegression

# In[35]:

from sklearn.tree import DecisionTreeClassifier

# In[36]:

from sklearn.neighbors import KNeighborsClassifier

# In[37]:

from sklearn.pipeline import Pipeline

# In[38]:

import numpy as np

# In[39]:

clf1 = LogisticRegression(penalty='l2',
                         C=0.01,
                         solver='lbfgs',
                         random_state=1)

# In[40]:

clf2 = DecisionTreeClassifier(max_depth=1,
                             criterion='entropy',
                             random_state=0)

# In[41]:

clf3 = KNeighborsClassifier(n_neighbors=1,
                            p=2,
                            metric='minkowski')

# In[42]:

pipe1 = Pipeline([['sc', StandardScaler()],
                ['clf', clf1]])

# In[43]:

pipe3 = Pipeline([['sc', StandardScaler()],
                 ['clf', clf3]])

# In[44]:

clf_labels = ['Logistic regression', 'Decision tree', 'KNN']

# In[ ]:

# In[45]:

print('10-fold cross validation:\n')

# In[46]:

for clf, label in zip([pipe1, clf2, pipe3], clf_labels):
    scores = cross_val_score(estimator=clf,
                            X=X_train,
                            y=y_train,
                            cv=10,
                            scoring='roc_auc')
    print("ROC AUC: %0.2f (+/- %0.02f [%s]"
         % (scores.mean(), scores.std(), label))

# In[47]:

mv_clf = MajorityVoteClassifier(
                  classifiers=[pipe1, clf2, pipe3])

# In[48]:

clf_labels += ['Majority voting']

# In[49]:

all_clf = [pipe1, clf2, pipe3, mv_clf]

# In[50]:

for clf, label in zip(all_clf, clf_labels):
    scores = cross_val_score(estimator=clf,
                            X=X_train,
                            y=y_train,
                            cv=10,
                            scoring='roc_auc')
    print("ROC AUC: %0.2f (+/- %0.2f) [%s]"
           % (scores.mean(), scores.std(), label))

# In[51]:

from sklearn.metrics import roc_curve

# In[52]:

from sklearn.metrics import auc

# In[53]:

colors =['black', 'orange', 'blue', 'green']
linestyles = [':', '--', '-.', '-']
for clf, label, clr, ls     in zip(all_clf, clf_labels, colors, linestyles):
    y_pred = clf.fit(X_train, y_train).predict_proba(X_test)[:, 1]
    fpr, tpr, thresholds = roc_curve(y_true=y_test,
                                    y_score=y_pred)
    roc_auc = auc(x=fpr, y=tpr)

    plt.plot(fpr, tpr,
            color=clr,
            linestyle=ls,
            label='%s (auc = %0.2f)' % (label, roc_auc))
    plt.legend(loc='lower right')
    plt.plot([0,1], [0, 1],
            linestyle='--',
            color='gray',
            linewidth=2)
    plt.xlim([-0.1, 1.1])
    plt.ylim([-0.1, 1.1])
    plt.grid(alpha=0.5)
    plt.xlabel('False positive rate (FPR)')
    plt.ylabel('True positive rate (TPR)')
    plt.show()

# In[54]:

sc = StandardScaler()

# In[55]:

X_train_std = sc.fit_transform(X_train)

# In[56]:

from itertools import product

# In[57]:

x_min = X_train_std[:, 0].min() - 1

# In[58]:

x_max = X_train_std[:, 0].max() + 1

# In[59]:

y_min = X_train_std[:, 1].max() - 1

# In[60]:

y_max = X_train_std[:, 1].max() + 1

# In[61]:

xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
                     np.arange(y_min, y_max, 0.1))

# In[62]:

f, axarr = plt.subplots(nrows=2, ncols=2,
                      sharex='col',
                      sharey='row',
                      figsize=(7, 5))
for idx, clf, tt in zip(product([0, 1], [0, 1]),
                       all_clf, clf_labels):
    clf.fit(X_train_std, y_train)
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    axarr[idx[0], idx[1]].contourf(xx, yy, Z, alpha=0.3)
    axarr[idx[0], idx[1]].scatter(X_train_std[y_train==0, 0],
                                   X_train_std[y_train==0, 1],
                                   c='blue',
                                   marker='^',
                                   s=50)
    axarr[idx[0], idx[1]].scatter(X_train_std[y_train==0, 0],
                                  X_train_std[y_train==0, 1],
                                  c='green',
                                  marker='o',
                                  s=50)
    axarr[idx[0], idx[1]].set_title(tt)
plt.text(-3.5, -5.,
        s='Sepal width [standardized]',
        ha='center', va='center', fontsize=12)
plt.text(-12.5, 4.5,
        s='Petal length [standardized]',
        ha='center', va='center',
        fontsize=12, rotation=90)
plt.show()

# In[63]:

mv_clf.get_params()

# In[64]:

import pandas as pd

# In[65]:

df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/'
                     'machine-learning-databases/wine/wine.data',
                      header=None)

# In[66]:

df_wine.columns = ['Class label', 'Alcohol',
                  'Malic acid', 'Ash',
                   'Alchalinity of Ash',
                  'Magnesium', 'Total phenols',
                  'Flavanoids', 'Nonflavanoid phenols',
                   'Prolanthocyanins',
                  'Color intensity', 'Hue',
                  'OD280/OD315 of diluted wines',
                  'Proline']

# In[67]:

# drop 1 class

# In[68]:

df_wine = df_wine[df_wine['Class label'] !=1]

# In[69]:

y = df_wine['Class label'].values

# In[70]:

X = df_wine[['Alcohol',
            'OD280/OD315 of diluted wines']].values

# In[71]:

from sklearn.preprocessing import LabelEncoder

# In[72]:

from sklearn.model_selection import train_test_split

# In[73]:

le = LabelEncoder()

# In[74]:

y = le.fit_transform(y)

# In[75]:

X_train, X_test, y_train, y_test =          train_test_split(X, y,
                          test_size=0.2,
                          random_state=1,
                          stratify=y)

# In[76]:

from sklearn.ensemble import BaggingClassifier

# In[77]:

tree = DecisionTreeClassifier(criterion='entropy',
                             random_state=1,
                             max_depth=None)

# In[78]:

bag = BaggingClassifier(base_estimator=tree,
                        n_estimators=500,
                        max_samples=1.0,
                        max_features=1.0,
                        bootstrap=True,
                        bootstrap_features=False,
                        n_jobs=1,
                        random_state=1)

# In[79]:

from sklearn.metrics import accuracy_score

# In[80]:

tree = tree.fit(X_train, y_train)

# In[81]:

y_train_pred = tree.predict(X_train)

# In[82]:

y_test_pred = tree.predict(X_test)

# In[83]:

tree_train = accuracy_score(y_train, y_train_pred)

# In[84]:

tree_test = accuracy_score(y_test, y_test_pred)

# In[85]:

print('Decision tree train/test accuracies %.3f/%.3f'
     % (tree_train, tree_test))

# In[ ]:

# In[86]:

bag = bag.fit(X_train, y_train)

# In[87]:

y_train_pred = bag.predict(X_train)

# In[88]:

y_test_pred = bag.predict(X_test)

# In[89]:

bag_train = accuracy_score(y_train, y_train_pred)

# In[90]:

bag_test = accuracy_score(y_test, y_test_pred)

# In[91]:

print('Bagging train/test accuracies %.3f/%.3f'
     % (bag_train, bag_test))

# In[92]:

x_min = X_train[:, 0].min() - 1

# In[93]:

x_max = X_train[:, 0].max() + 1

# In[94]:

y_min = X_train[:, 1].min() - 1

# In[95]:

y_max = X_train[:, 1].max() + 1

# In[96]:

xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
                    np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(nrows=1, ncols=2,
                        sharex='col',
                        sharey='row',
                        figsize=(8, 3))
for idx, clf, tt in zip([0, 1],
                        [tree, bag],
                        ['Decision tree', 'Bagging']):
    clf.fit(X_train, y_train)

    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    axarr[idx].contourf(xx, yy, Z, alpha=0.3)
    axarr[idx].scatter(X_train[y_train==0, 0],
                       X_train[y_train==0, 1],
                       c='blue', marker='^')
    axarr[idx].scatter(X_train[y_train==1, 0],
                       X_train[y_train==1, 1],
                       c='green', marker='o')
    axarr[idx].set_title(tt)
axarr[0].set_ylabel('Alcohol', fontsize=12)
plt.tight_layout()
plt.text(0, -0.2,
         s='OD280/OD315 of diluted wines',
         ha='center',
         va='center',
         fontsize=12,
         transform=axarr[1].transAxes)
plt.show()

# In[97]:

from sklearn.ensemble import AdaBoostClassifier

# In[98]:

tree = DecisionTreeClassifier(criterion='entropy',
                             random_state=1,
                             max_depth=1)

# In[99]:

ada = AdaBoostClassifier(base_estimator=tree,
                         n_estimators=500,
                         learning_rate=.1,
                         random_state=1)

# In[100]:

tree = tree.fit(X_train, y_train)

# In[101]:

y_train_pred = tree.predict(X_train)

# In[ ]:

# In[ ]:

# In[102]:

y_test_pred = tree.predict(X_test)

# In[103]:

tree_train = accuracy_score(y_train, y_train_pred)

# In[104]:

tree_test = accuracy_score(y_test, y_test_pred)

# In[105]:

print('Decision tree train/test accuracies %.3f/%.3f'
      %(tree_train, tree_test))

# In[106]:

ada = ada.fit(X_train, y_train)

# In[107]:

y_train_pred = ada.predict(X_train)

# In[108]:

y_test_pred = ada.predict(X_test)

# In[109]:

ada_train = accuracy_score(y_train, y_train_pred)

# In[110]:

ada_test = accuracy_score(y_test, y_test_pred)

# In[111]:

print('AdaBoost train/test accuracies %.3f/%.3f'
      % (ada_train, ada_test))

# In[112]:

x_min = X_train[:, 0].min() - 1

# In[113]:

x_max = X_train[:, 0].max() + 1

# In[114]:

y_min = X_train[:, 1].min() - 1

# In[115]:

y_max = X_train[:, 1].max() + 1

# In[116]:

xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
                    np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(1, 2,
                        sharex='col',
                        sharey='row',
                        figsize=(8, 3))
for idx, clf, tt in zip([0, 1],
                        [tree, ada],
                        ['Decision tree', 'AdaBoost']):
    clf.fit(X_train, y_train)

    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    axarr[idx].contourf(xx, yy, Z, alpha=0.3)
    axarr[idx].scatter(X_train[y_train==0, 0],
                       X_train[y_train==0, 1],
                       c='blue', marker='^')
    axarr[idx].scatter(X_train[y_train==1, 0],
                       X_train[y_train==1, 1],
                       c='green', marker='o')
    axarr[idx].set_title(tt)
axarr[0].set_ylabel('Alcohol', fontsize=12)
plt.tight_layout()
plt.text(0, -0.2,
         s='OD280/OD315 of diluted wines',
         ha='center',
         va='center',
         fontsize=12,
         transform=axarr[1].transAxes)
plt.show()


import numpy as np

from utils import _array_almost_equal, _correct_format

class Non_linear_polynomial_fit:

    def non_linear_polynomial_fit(self, seq, factor):
        """ Un = a * Un-1 + b * factor**n + c
        """
        B = np.array(seq[1:4])
        A = np.array([[seq[k], factor ** (k + 1), 1] for k in range(3)])
        return np.around(np.linalg.solve(A,B), decimals=2)

    def non_linear_recursion(self, u, n, factor, coef):
        a, b, c = coef
        return a * u + b * (factor**n) + c

    def __call__(self, seq):
        Factor = {2,3,4}
        success = False
        for factor in Factor:
            try:
                coef = self.non_linear_polynomial_fit(seq, factor)
                Attempt = seq[:4]
                for n in range(4, len(seq)):
                    Attempt = np.append(Attempt, self.non_linear_recursion(Attempt[-1], n, factor, coef))
                if _array_almost_equal(Attempt, seq):
                    success = True
                    print('Non linear polynomial fit succeeded, factor = {}.\nUn = {} * Un-1 + {} * {}**n + {}.\nThe following term is {}.'.format(factor, _correct_format(coef[0]), _correct_format(coef[1]), factor, _correct_format(coef[2]), _correct_format(self.non_linear_recursion(seq[-1], (n+1), factor, coef))))
            except:
                pass
        if not success:
            print("No non linear polynomial fit\n")


import numpy as np

def euclidean_distances(X, Y):
    """Compute pairwise Euclidean distance between the rows of two matrices X (shape MxK)
    and Y (shape NxK). The output of this function is a matrix of shape MxN containing
    the Euclidean distance between two rows.

    Arguments:
        X {np.ndarray} -- First matrix, containing M examples with K features each.
        Y {np.ndarray} -- Second matrix, containing N examples with K features each.

    Returns:
        D {np.ndarray}: MxN matrix with Euclidean distances between rows of X and rows of Y.
    """
    dists = np.zeros((len(X), len(Y)))
    for i in range(len(X)):
        for j in range(len(Y)):
            dists[i, j] = np.sqrt(np.sum(np.square(X[i] - Y[j])))

    return dists

def manhattan_distances(X, Y):
    """Compute pairwise Manhattan distance between the rows of two matrices X (shape MxK)
    and Y (shape NxK). The output of this function is a matrix of shape MxN containing
    the Manhattan distance between two rows.

    Arguments:
        X {np.ndarray} -- First matrix, containing M examples with K features each.
        Y {np.ndarray} -- Second matrix, containing N examples with K features each.

    Returns:
        D {np.ndarray}: MxN matrix with Manhattan distances between rows of X and rows of Y.
    """
    dists = np.zeros((len(X), len(Y)))
    for i in range(len(X)):
        for j in range(len(Y)):
            dists[i, j] = np.sum(np.abs(X[i] - Y[j]))

    return dists

def cosine_distances(X, Y):
    """Compute Cosine distance between the rows of two matrices X (shape MxK)
    and Y (shape NxK). The output of this function is a matrix of shape MxN containing
    the Cosine distance between two rows.

    Arguments:
        X {np.ndarray} -- First matrix, containing M examples with K features each.
        Y {np.ndarray} -- Second matrix, containing N examples with K features each.

    Returns:
        D {np.ndarray}: MxN matrix with Cosine distances between rows of X and rows of Y.
    """
    dists = np.zeros((len(X), len(Y)))
    for i in range(len(X)):
        for j in range(len(Y)):
            dists[i, j] = 1 - np.dot(X[i], Y[j]) / ((np.linalg.norm(X[i])) * (np.linalg.norm(Y[j])))

    return dists


import numpy as np

def generate_3circles_data(n_samples):
    """Generate 3 circles pattern data

    Args:
        n_samples (int): Number of samples to generate

    Returns:
        data (tuple):
            X (np-array): x, y positions
            y (np-array): classes
    """
    centers = np.array([[-1, 1], [1, 0], [-.5, -.5]])
    radii = np.array([1, np.sqrt(6/np.pi - 1), 1/2])
    points=[]
    classes=[]
    dim = 2
    for i in range(n_samples):
        X = 2 * (np.random.rand(dim)) - 1
        y = 0
        for j, (c, r) in enumerate(zip(centers, radii)):
            if np.linalg.norm(X - c) < r:
                y = j + 1

        points.append(X)
        classes.append(y)

    data = np.array(points), np.array(classes)
    settings = centers, radii

    return data, settings

def generate_annulus_data(samples):
    """Generate the annulus pattern (tricrown) data

    Args:
        n_samples (int): Number of samples to generate

    Returns:
        data (tuple):
            X (np-array): x, y positions
            y (np-array): classes
    """
    centers = [[0,0],[0,0]]
    radii = [np.sqrt(.8 - 2/np.pi), np.sqrt(.8)]
    points=[]
    classes=[]
    dim = 2
    for i in range(samples):
        X = 2 * (np.random.rand(dim)) - 1
        y=0
        for j,(r,c) in enumerate(zip(radii, centers)):
            if np.linalg.norm(X - c) > r:
                y = j + 1
        points.append(X)
        classes.append(y)

    data = np.array(points), np.array(classes)
    settings = centers, radii

    return data, settings


from csv import reader
from pprint import pprint
from random import shuffle, seed
from math import exp, pi, sqrt
from operator import itemgetter
import numpy as np

seed(2)
data = np.array(list(reader(open('5-dataset-alt.csv'))), dtype='float')
shuffle(data)
trainLen = int(.9 * len(data))
trainData, trainTarget = data[:trainLen, : -1], data[:trainLen, -1]
testData, testTarget = data[trainLen:, : -1], data[trainLen:, -1]

def safe_div(x, y):
    return x / y if y != 0 else 0

def getProbabilty(x, mean, std):
    exponent = exp(-safe_div((x - mean) ** 2, 2 * std ** 2))
    return safe_div(1, sqrt(2 * pi) * std) * exponent

classes = {}
for attrs, target in zip(trainData, trainTarget):
    if target not in classes:
        classes[target] = []
    classes[target].append(attrs)

summaries = {}
for cls in classes.keys():
    summaries[cls] = []
    for column in zip(*classes[cls]):
        summaries[cls].append((np.mean(column), np.std(column)))

correct = 0
for attrs, target in zip(testData, testTarget):
    probabilty = {}
    for cls in classes.keys():
        probabilty[cls] = 1
        for i, (mean, std) in enumerate(summaries[cls]):
            probabilty[cls] *= getProbabilty(attrs[i], mean, std)

    cls = sorted(probabilty.items(), key=itemgetter(1), reverse=True)[0][0]
    print(f'Actual: {target} \tPredicted: {cls}')
    if cls == target:
        correct += 1

print(f'Accuracy {correct/len(testData)}')


"""
Module that compute diagonal multivariate normal distribution operation with tensorflow tensor as parameters
"""
import tensorflow as tf
import numpy as np

def kl(mean_p, var_p, mean_q, var_q, dims):
    """
    Compute the KL divergence of diagonal multivariate normal distribution q, and p, which is KL(P||Q)
    :param mean_p:
    :param var_p:
    :param mean_q:
    :param var_q:
    :param dims:
    :return:
    """
    # p is old

    log_var_p = tf.log(var_p)
    log_var_q = tf.log(var_q)
    log_det_cov_p = tf.reduce_sum(log_var_p)
    log_det_cov_q = tf.reduce_sum(log_var_q)
    tr_p_q = tf.reduce_sum(tf.exp(log_var_p - log_var_q))
    kl = 0.5 * tf.reduce_mean(
        log_det_cov_q - log_det_cov_p + tr_p_q + tf.reduce_sum(tf.square(mean_q - mean_p) / tf.exp(log_det_cov_q),
                                                               axis=1) - dims)
    return kl

def entropy(mean_p, var_p, dims):
    return 0.5 * (dims * (np.log(2 * np.pi) + 1) + tf.reduce_sum(tf.log(var_p)))

def log_prob(variable_ph, mean_p, var_p):
    log_prob = -0.5 * (tf.reduce_sum(tf.log(var_p)) + (np.log(2 * np.pi)))
    log_prob += -0.5 * tf.reduce_sum(tf.square(variable_ph - mean_p) / var_p, axis=1)
    return log_prob

def prob(variable_ph, mean_p, var_p):
    return tf.log(log_prob(variable_ph, mean_p, var_p))

def sample(mean_p, var_p, dims):
    return mean_p + tf.math.sqrt(var_p) * tf.random_normal(shape=(dims,))


'''
Sum a Series
'''

from sympy import symbols, summation, pprint, init_printing, sympify
from sympy.core import SympifyError

def sum_series( nterm, terms ):

	init_printing( order = 'rev-lex' )

	x, n = symbols( 'x, n' )

	s = summation( nterm, ( n, 1, terms ) )

	pprint( s )

if __name__ == '__main__':
	try:
		nterm = input( 'Enter the nth term: ' )
		terms = input( 'Enter the number of terms: ' )
	except SympifyError:
		print( 'Invalid Input' )
	else:
		sum_series( sympify( nterm ), terms )


from sklearn.cluster import KMeans
from sklearn import preprocessing
from sklearn.mixture import GaussianMixture
from sklearn.datasets import load_iris
import sklearn.metrics as sm
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

dataset=load_iris()
# print(dataset)

X=pd.DataFrame(dataset.data)
X.columns=['Sepal_Length','Sepal_Width','Petal_Length','Petal_Width']
y=pd.DataFrame(dataset.target)
y.columns=['Targets']
# print(X)

plt.figure(figsize=(14,7))
colormap=np.array(['red','lime','black'])

# REAL PLOT
plt.subplot(1,3,1)
plt.scatter(X.Petal_Length,X.Petal_Width,c=colormap[y.Targets],s=40)
plt.title('Real')

# K-PLOT
plt.subplot(1,3,2)
model=KMeans(n_clusters=3)
model.fit(X)
predY=np.choose(model.labels_,[0,1,2]).astype(np.int64)
plt.scatter(X.Petal_Length,X.Petal_Width,c=colormap[predY],s=40)
plt.title('KMeans')

# GMM PLOT
scaler=preprocessing.StandardScaler()
scaler.fit(X)
xsa=scaler.transform(X)
xs=pd.DataFrame(xsa,columns=X.columns)
gmm=GaussianMixture(n_components=3)
gmm.fit(xs)

y_cluster_gmm=gmm.predict(xs)
plt.subplot(1,3,3)
plt.scatter(X.Petal_Length,X.Petal_Width,c=colormap[y_cluster_gmm],s=40)
plt.title('GMM Classification')

7th SEM/MACHINE LEARNING LABORATORY/8-EM and K-means Algorithm/LAB8.py


"""Module containing definitions of arithmetic functions used by perceptrons"""

from abc import ABC, abstractmethod

import numpy as np

from NaiveNeurals.utils import ErrorAlgorithm

class ActivationFunction(ABC):
    """Abstract function for defining functions"""

    label = ''

    @staticmethod
    @abstractmethod
    def function(arg: np.array) -> np.array:
        """Implementation of function

        :param arg: float
        :return: float
        """
        raise NotImplementedError()

    @classmethod
    @abstractmethod
    def prime(cls, arg: np.array) -> np.array:
        """First derivative of implemented function

        :param arg: float
        :return: float
        """
        raise NotImplementedError()

class Sigmoid(ActivationFunction):
    """Represents sigmoid function and its derivative"""

    label = 'sigmoid'

    @staticmethod
    def function(arg: np.array) -> np.array:
        """Calculate sigmoid(arg)

        :param arg: float input value
        :return: float sig(arg) value
        """
        return 1 / (1 + np.exp(-arg))

    @classmethod
    def prime(cls, arg: np.array) -> np.array:
        """Calculate value of sigmoid's prime derivative for given arg

        :param arg: float input value
        :return: float value
        """
        return cls.function(arg) * (1 - cls.function(arg))

class Tanh(ActivationFunction):
    """Represents hyperbolic tangent"""

    label = 'tanh'

    @staticmethod
    def function(arg: np.array) -> np.array:
        """Calculate tanh(arg)

        :param arg: float input value
        :return: float tanh(arg) value
        """
        return np.tanh(arg)

    @classmethod
    def prime(cls, arg: np.array) -> np.array:
        """Calculate value of tanh's prime derivative for given arg

        :param arg: float input value
        :return: float value
        """
        return 1 - np.tanh(arg)**2

class Linear(ActivationFunction):
    """Represents linear function"""

    label = 'lin'

    @staticmethod
    def function(arg: np.array) -> np.array:
        """Calculate lin(arg)

        :param arg: float input value
        :return: float lin(arg) value
        """
        return arg

    @classmethod
    def prime(cls, arg: np.array) -> np.array:
        """Calculate value of lin's prime derivative for given arg

        :param arg: float input value
        :return: float value
        """
        ones = np.array(arg)
        ones[::] = 1.0
        return ones

class SoftMax(ActivationFunction):
    """Represents SoftMax function

    The ``softmax`` function takes an N-dimensional vector of arbitrary real values and produces
    another N-dimensional vector with real values in the range (0, 1) that add up to 1.0.

    source: https://eli.thegreenplace.net/2016/the-softmax-function-and-its-derivative/
    """

    label = 'softmax'

    @staticmethod
    def function(arg: np.array, beta: int = 20) -> np.array:        # pylint: disable=arguments-differ
        """Calculate softmax(arg)

        :param arg: float input value
        :param beta: scaling parameter
        :return: float softmax(arg) value
        """
        exps = np.exp(beta * arg - beta * arg.max())
        return exps / np.sum(exps)

    @classmethod
    def prime(cls, arg: np.array) -> np.array:
        """Calculate value of softmax's prime derivative for given arg

        :param arg: float input value
        :return: float value
        """
        return cls.function(arg) * (1 - cls.function(arg))

class SoftPlus(ActivationFunction):
    """Represents softplus function"""

    label = 'softplus'

    @staticmethod
    def function(arg: np.array) -> np.array:
        """Calculate softplus(arg)

        :param arg: float input value
        :return: float softmax(arg) value
        """
        return np.log(1 + np.exp(arg))

    @classmethod
    def prime(cls, arg: np.array) -> np.array:
        """Calculate value of softplus's prime derivative for given arg

        :param arg: float input value
        :return: float value
        """
        return 1/(1 + np.exp(-arg))

def get_activation_function(label: str) -> ActivationFunction:
    """Get activation function by label

    :param label: string denoting function
    :return: callable function
    """
    if label == 'lin':
        return Linear()
    if label == 'sigmoid':
        return Sigmoid()
    if label == 'tanh':
        return Tanh()
    return Sigmoid()

def calculate_error(target: np.array, actual: np.array,
                    func_type: ErrorAlgorithm = ErrorAlgorithm.SQR) -> np.array:
    """Calculates error for provided actual and targeted data.

    :param target: target data
    :param actual: actual training data
    :param func_type: denotes type of used function for error
    :return: calculated error
    """
    if func_type == ErrorAlgorithm.SQR:
        return np.sum(0.5 * np.power(actual - target, 2), axis=1)
    elif func_type == ErrorAlgorithm.CE:
        return -1 * np.sum(target * np.log(abs(actual)), axis=1)
    raise NotImplementedError()


"""
Compute sample size using Hoeffding's inequality.

[Hoeffding's inequality](https://en.wikipedia.org/wiki/Hoeffding%27s_inequality)
Let X1, ..., Xn be independent random variables bounded by the interval [0, 1].
We define the empirical mean of these variables by
Sn = 1/n(X1+ ... +Xn)
Hoeffding's inequality ==> P(|Sn - E(Sn)| > epsilon) < 2exp(-2epsilon^2*n), epsilon > 0.
Let gamma > 0,
so: P(|Sn - E(Sn)| > epsilon) < gamma <==> n > [-ln(gamma/2)]/[2*epsilon^2]
n = sample size.

Example:
sample_size(0.08, 0.01) = 16094
sample_size(0.001, 0.001) = 3800451

Author: [SofianeHADDADI](https://github.com/SofianeHADDADI)
"""

import numpy as np

def sample_size(gamma, epsilon):
    n = (-np.log(gamma/2))/(2*epsilon*epsilon)
    return int(n)


import numpy as np

class GaussianFeature(object):
    """
    Gaussian feature

    gaussian function = exp(-0.5 * (x - m) / v)
    """

    def __init__(self, mean, var):
        """
        construct gaussian features

        Parameters
        ----------
        mean : (n_features, ndim) or (n_features,) ndarray
            places to locate gaussian function at
        var : float
            variance of the gaussian function
        """
        if mean.ndim == 1:
            mean = mean[:, None]
        else:
            assert mean.ndim == 2 # 2차원 coordinate까지 지원
        assert isinstance(var, float) or isinstance(var, int)
        self.mean = mean
        self.var = var

    def _gauss(self, x, mean):
        return np.exp(-0.5 * np.sum(np.square(x - mean), axis=-1) / self.var) # np.sum은 모든 원소를 그냥 더하는 함수;

    def transform(self, x):
        """
        transform input array with gaussian features

        Parameters
        ----------
        x : (sample_size, ndim) or (sample_size,)
            input array

        Returns
        -------
        output : (sample_size, n_features)
            gaussian features
        """
        if x.ndim == 1:
            x = x[:, None]
        else:
            assert x.ndim == 2
        assert np.size(x, 1) == np.size(self.mean, 1)
        basis = [np.ones(len(x))] # bias term
        for m in self.mean: # 각 평균 지점 마다
            basis.append(self._gauss(x, m)) # 들어온 x를 가우시안 베이시스의 값으로 바꾸고 list에 추가
        return np.asarray(basis).transpose() # sample_size X n_features

# 테스트용
if __name__=='__main__':
    X_G = GaussianFeature(np.linspace(-1, 1, 11), 0.1)
    X_G.transform(np.array([1]))
    X_G2 = GaussianFeature(np.linspace(-1, 1, 12).reshape(-1, 2), 0.1)
    X_G2.transform(np.array([[1, 2]]))


"""For a given dataset: (1,1.2), (2,1.9), (3,3.2)
Find the line which fits the data using maximum likelihood function. Plot the line with the given dataset and post it here in the Google class room. Also create your github account and post the link of the code along with the plot so that I can check the code by clicking on it.

Please take beta = 1; therefore you need to find only w (i.e. intercept and slope only).

"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

x = np.array([1,2,3])
y = np.array([1.2,1.9,3.2])
beta = 1

"""Upon differentiating the log likelihood formula, to obtain the value of w0 and w1
in the function y(x,w) => y = w1x+ w0, we get the values of w0,w1 as follows:

w0 = (RQ-PS)/(RN-P^2)
w1 = (Q - Nw0)/P

where P = x.sum()
      Q = y.sum()
      R = (np.square(x)).sum()
      S = (x*y).sum()
      N = len(x)"""

def Get_params(x,y):
    P = x.sum()
    Q = y.sum()
    R = (x*x).sum()
    S = (x*y).sum()
    N = len(x)

    w0 = ((R*Q) - (P*S))/((R*N) - (P**2))
#     w1 = ((P*Q) - (R*S))/((R*N) - (P**2))
    w1 = (Q - (N*w0))/P

    print("W is given by w1=",w1," w0=",w0)
    return w1, w0

m,c = Get_params(x,y)

abline_values = [m * i + c for i in x]
plt.scatter(x,y)
plt.plot(x, y, '--')
plt.plot(x, abline_values, 'b')
plt.show()


import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCA
sns.set()

rng = np.random.RandomState(1)
X = np.dot(rng.rand(2, 2), rng.randn(2, 200)).T
plt.figure()
plt.scatter(X[:, 0], X[:, 1])
plt.axis('equal')
plt.show()

pca2d = PCA(n_components=2)
pca2d.fit(X)
# pca2d.components_, pca2d.explained_variance_, pca2d.explained_variance_ratio_

def draw_vector(v0, v1, ax=None):
    ax = ax or plt.gca()
    arrowprops=dict(arrowstyle='->', linewidth=2, shrinkA=0, shrinkB=0, color="0")
    ax.annotate('', v1, v0, arrowprops=arrowprops)

# plot data
plt.figure()
plt.scatter(X[:, 0], X[:, 1], alpha=0.2)
for length, vector in zip(pca2d.explained_variance_, pca2d.components_):
    v = vector * 3 * np.sqrt(length)
    draw_vector(pca2d.mean_, pca2d.mean_ + v)
plt.axis('equal')
plt.show()

pca1d = PCA(n_components=1)
pca1d.fit(X)
X_pca = pca1d.transform(X)

X_new = pca1d.inverse_transform(X_pca)
plt.figure()
plt.scatter(X[:, 0], X[:, 1], alpha=0.2)
plt.scatter(X_new[:, 0], X_new[:, 1], alpha=0.8)
plt.axis('equal')
plt.show()


# using GRADIENT ASCENT to find extrema values

# t_flight = 2*u*sin( theta ) / g
# R = u*cos( theta ) * 2*u*sin( theta ) / g = u**2 * 2 *theta / g

'''
Use gradient ascent to find the angle at which the projectile has maximum range for a fixed velocity, 25m/s
'''

import math
from sympy import Derivative, Symbol, sin

def grad_ascent( x0, f1x, x ):
	epsilon = 1e-6
	step_size = 1e-4
	x_old = x0
	x_new = x_old + step_size * f1x.subs( { x: x_old } ).evalf()

	while( abs( x_old - x_new ) > epsilon ):
	   x_old = x_new
	   x_new = x_old + step_size * f1x.subs( { x: x_old } ).evalf()

	return x_new

def find_max_theta( R, theta ):
	# Calculate the first derivative
	R1theta = Derivative( R, theta ).doit()
	theta0 = 1e-3
	theta_max = grad_ascent( theta0, R1theta, theta )

	return theta_max

if __name__ == '__main__':

	g = 9.8
	# Assume initial velocity
	u = 25
	# Expression for the range
	theta = Symbol( 'theta' )
	R = u ** 2 * sin( 2 * theta ) / g

	theta_max = find_max_theta( R, theta )

	print( 'Theta: {0}'.format( math.degrees( theta_max ) ) )
	print( 'Maximum Range: {0}'.format( R.subs( { theta: theta_max } ) ) )


"""归一化(标准化)的目标之一在于将输入保持在一个可接受的范围内
例如将输入归一化到[0.0,1.0]区间内使输入中所有可能的分量归一化为一个大于等于0.0小于等于1.0的值"""
"""
tf.nn.l2_normalize(x, dim, epsilon=1e-12, name=None)
解释：这个函数的作用是利用 L2 范数对指定维度 dim 进行标准化。
比如，对于一个一维的张量，指定维度 dim = 0，那么计算结果为：
output = x / sqrt( max( sum( x ** 2 ) , epsilon ) )
假设 x 是多维度的，那么标准化只会独立的对维度 dim 进行，不会影响到别的维度。"""
import numpy as np
import tensorflow as tf

input_data = tf.Variable(np.arange(1, 7).reshape(2, 3), dtype=tf.float32)
output = tf.nn.l2_normalize(input_data, dim=0)
with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    print(sess.run(tf.shape(input_data)))
    print(sess.run(input_data))
    print(sess.run(output))
    print(sess.run(tf.shape(output)))
    # [2 3]
    # [[1.  2.  3.]
    #  [4.  5.  6.]]
    # [[0.24253564  0.37139067  0.44721359]
    #  [0.97014254  0.92847669  0.89442718]]
    # [2 3]
"""输入参数：
  ● x: 一个Tensor。
  ● dim: 需要标准化的维度。
  ● epsilon: 一个很小的值，确定标准化的下边界。如果 norm < sqrt(epsilon)，那么我们将使用 sqrt(epsilon) 进行标准化。
  ● name: （可选）为这个操作取一个名字。
输出参数：
一个 Tensor ，数据维度和 x 相同。"""


from __future__ import division

import math

import numpy as np

from . import common_args
from .. util import scale_samples, read_param_file

def sample(problem, N, M=4, seed=None):
    """Generate model inputs for the Fourier Amplitude Sensitivity Test (FAST).

    Returns a NumPy matrix containing the model inputs required by the Fourier
    Amplitude sensitivity test.  The resulting matrix contains N * D rows and D
    columns, where D is the number of parameters.  The samples generated are
    intended to be used by :func:`SALib.analyze.fast.analyze`.

    Parameters
    ----------
    problem : dict
        The problem definition
    N : int
        The number of samples to generate
    M : int
        The interference parameter, i.e., the number of harmonics to sum in the
        Fourier series decomposition (default 4)
    """
    if seed:
        np.random.seed(seed)

    if N <= 4 * M**2:
        raise ValueError("""
        Sample size N > 4M^2 is required. M=4 by default.""")

    D = problem['num_vars']

    omega = np.zeros([D])
    omega[0] = math.floor((N - 1) / (2 * M))
    m = math.floor(omega[0] / (2 * M))

    if m >= (D - 1):
        omega[1:] = np.floor(np.linspace(1, m, D - 1))
    else:
        omega[1:] = np.arange(D - 1) % m + 1

    # Discretization of the frequency space, s
    s = (2 * math.pi / N) * np.arange(N)

    # Transformation to get points in the X space
    X = np.zeros([N * D, D])
    omega2 = np.zeros([D])

    for i in range(D):
        omega2[i] = omega[0]
        idx = list(range(i)) + list(range(i + 1, D))
        omega2[idx] = omega[1:]
        l = range(i * N, (i + 1) * N)

        # random phase shift on [0, 2pi) following Saltelli et al.
        # Technometrics 1999
        phi = 2 * math.pi * np.random.rand()

        for j in range(D):
            g = 0.5 + (1 / math.pi) * np.arcsin(np.sin(omega2[j] * s + phi))
            X[l, j] = g

    scale_samples(X, problem['bounds'])
    return X

def cli_parse(parser):
    """Add method specific options to CLI parser.

    Parameters
    ----------
    parser : argparse object

    Returns
    ----------
    Updated argparse object
    """
    parser.add_argument('-M', '--m-coef', type=int, required=False, default=4,
                        help='M coefficient, default 4', dest='M')
    return parser

def cli_action(args):
    """Run sampling method

    Parameters
    ----------
    args : argparse namespace
    """
    problem = read_param_file(args.paramfile)
    param_values = sample(problem, N=args.samples, M=args.M, seed=args.seed)
    np.savetxt(args.output, param_values, delimiter=args.delimiter,
               fmt='%.' + str(args.precision) + 'e')

if __name__ == "__main__":
    common_args.run_cli(cli_parse, cli_action)


# Polinomio de interpolación
import matplotlib.pyplot as plt
import numpy as np
def createMatrix(m,n,v):
    C = []
    for i in range(m):
        C.append([v]*n)
    return C

def getDimensions(A):
    return (len(A),len(A[0]))

def copyMatrix(B):
    m,n = getDimensions(B)
    A = createMatrix(m,n,0)
    for i in range(m):
        for j in range(n):
            A[i][j] = B[i][j]
    return A

def sumaMatrix(A,B):
    Am,An = getDimensions(A)
    Bm,Bn = getDimensions(B)
    if Am != Bm or An != Bn:
        print("Error las dimensiones deben ser iguales")
        return []
    C = createMatrix(Am,An,0)
    for i in range(Am):
        for j in range(An):
            C[i][j] = A[i][j] + B[i][j]
    return C

def restaMatrix(A,B):
    Am,An = getDimensions(A)
    Bm,Bn = getDimensions(B)
    if Am != Bm or An != Bn:
        print("Error las dimensiones deben ser iguales")
        return []
    C = createMatrix(Am,An,0)
    for i in range(Am):
        for j in range(An):
            C[i][j] = A[i][j] - B[i][j]
    return C

def multMatrix(A,B):
    Am,An = getDimensions(A)
    Bm,Bn = getDimensions(B)
    if An != Bm:
        print("Error las dimensiones deben ser conformable")
        return []
    C = createMatrix(Am,Bn,0)
    for i in range(Am):
        for j in range(Bn):
            for k in range(An):
                    C[i][j] += A[i][k] * B[k][j]
    return C

def getAdyacente(A,r,c):
    Am,An = getDimensions(A)
    C = createMatrix(Am-1,An-1,0)
    for i in range(Am):
        if i == r:
            continue
        for j in range(An):
            if j == c:
                continue
            ci = 0
            cj = 0
            if(i < r):
                ci = i
            else:
                ci = i - 1
            if(j < c):
                cj = j
            else:
                cj = j - 1
            C[ci][cj] = A[i][j]
    return C

def detMatrix(A):
    m,n = getDimensions(A)
    if m != n:
        print("La matriz no es cuadrada")
        return []
    if m == 1:
        return A[0][0]
    if m == 2:
        return A[0][0]*A[1][1] - A[1][0]*A[0][1]
    det = 0
    for j in range(m):
        det += ((-1)**j)*A[0][j]*detMatrix(getAdyacente(A,0,j))
    return det

def getMatrizTranspuesta(A):
    m,n = getDimensions(A)
    C = createMatrix(n,m,0)
    for i in range(m):
        for j in range(n):
            C[j][i] = A[i][j]
    return C

def getMatrizAdjunta(A):
    m,n = getDimensions(A)
    if m != n:
        print("La matriz no es cuadrada")
        return []
    C = createMatrix(m,n,0)
    for i in range(m):
        for j in range(n):
            C[i][j] = ((-1)**(i+j))*detMatrix(getAdyacente(A,i,j))
    return C

def getMatrizInversa(A):
    m,n = getDimensions(A)
    if m != n:
        print("La matriz no es cuadrada")
        return []
    detA = detMatrix(A)
    if detA == 0:
        print("La matriz no tiene inversa")
        return []
    At = getMatrizTranspuesta(A)
    adjA = getMatrizAdjunta(At)
    invDetA = 1/detA
    C = createMatrix(m,n,0)
    for i in range(m):
        for j in range(n):
            C[i][j] = invDetA * adjA[i][j]
    return C

def evalPolinomio(coef,x):
    y = []
    coef = np.asarray(coef)
    for i in range(len(x)):
        y.append(0)
        for c in range(len(coef)):
            y[i] += (x[i]**c) * coef[c]
    return y

x = [1950, 1960, 1970, 1980, 1990, 2000]
y = createMatrix(6,1,0)
y[0] = [123.5]
y[1] = [131.2]
y[2] = [150.7]
y[3] = [141.3]
y[4] = [203.2]
y[5] = [240.5]
n = 6
A = createMatrix(n,n,0)
for i in range(n):
    for j in range(n):
        A[i][j] = x[i]**j
print(A)

invA = getMatrizInversa(A)
B = multMatrix(invA,y)

#print(B)
plt.plot(x,y,'ro')
x2 = np.linspace(1950, 2000, 100)
y2 = evalPolinomio(B, x2)

estimation = evalPolinomio(B,[1965])
plt.plot(x2,y2)
plt.show()

print("Año 1965: {0}".format(estimation[0]))


import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
from numpy.fft import fft2, ifft2, fftshift, ifftshift

# %% read in the image and do transform

Q6_2 = np.array(Image.open("Q6_2.tif"))
row, col = Q6_2.shape

img_fourier = fftshift(fft2(Q6_2))
img_view = np.log10(np.abs(img_fourier) + 1)

plt.subplot(121)
plt.imshow(Q6_2, cmap='gray')
plt.title('Raw Q6_2.tif')
plt.subplot(122)
plt.imshow(img_view, cmap='gray')
plt.title('Fourier Transformed Q6_2.tif\n(log transformed)')
plt.savefig('Q6_2.png')
plt.show()

# %% generate degradation function
k = 0.0025
func = np.fromfunction(lambda mu, nu:
                       np.exp(-k * ((mu - row / 2) ** 2 + (nu - col / 2) ** 2) ** (5 / 6)),
                       (row, col))

plt.imshow(func, cmap='gray')
plt.title('Degradation function')
plt.savefig('Q6_2_h.png')
plt.show()

# %% restore the image

img_out_fourier = img_fourier / func
img_out_view = np.log10(np.abs(img_out_fourier) + 1)
img_out = np.abs(ifft2(ifftshift(img_out_fourier)))

plt.subplot(121)
plt.imshow(img_out, cmap='gray')
plt.title('Restored Q6_2.tif')
plt.subplot(122)
plt.imshow(img_out_view, cmap='gray')
plt.title('Fourier Transform of\nthe restored image\n(log transformed)')
plt.savefig('Q6_2_1.png')
plt.show()


import numpy as np
import matplotlib.pyplot as plt

#number of samples
N_total = 10_000

#drawing random points uniform between -1 and 1
X = np.random.uniform(low=-1, high=1, size=N_total)
Y = np.random.uniform(low=-1, high=1, size=N_total)

# calculate the distance of the points from the center
distance = np.sqrt(X**2+Y**2);
# check if point is inside the circle
is_point_inside = distance<1.0
# sum up the hits inside the circle
N_inside=np.sum(is_point_inside)

#area of the bounding box [-1 -> 1 = 2]^2
box_area = 4.0
# estimate the circle area
circle_area = box_area * N_inside/N_total

# results
print("Area of the circle = ", circle_area)
print("pi = ", np.pi)
print

# plot
plt.scatter(X,Y, c=is_point_inside, alpha=0.5, cmap=plt.cm.Set3)
plt.axis('equal')
plt.axhline(0, color='white')
plt.axvline(0, color='white')
# plt.show()


# -*- coding: utf-8 -*-
"""
Created on Tue Dec  8 06:51:59 2020

@author: franklin
"""

import numpy as np
import scipy.stats as si

combi = np.loadtxt('combi.csv', delimiter=',')

S = combi[:,0]
sigma = combi[:,1]

K, T, r = (100, 1, 0.05)

d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
result = (S * si.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(d2, 0.0, 1.0))

"""
出力例：
In []: d1
Out[]:
array([-45.50170186, -22.67585093, -15.03390062, ...,   4.90510204,
         4.95505051,   5.005     ])

In []: d2
Out[]:
array([-45.60170186, -22.87585093, -15.33390062, ...,  -4.89489796,
        -4.94494949,  -4.995     ])

In []: result
Out[]:
array([0.00000000e+000, 3.37791731e-116, 4.27087120e-053, ...,
       9.99999065e+001, 9.99999276e+001, 9.99999441e+001])"
"""

optionType = np.random.choice(('call','put'), len(combi))
ep = np.where(optionType == 'call', 1.0, -1.0)

result = (ep * S * si.norm.cdf(ep * d1, 0.0, 1.0) - ep * K * np.exp(-r * T) * si.norm.cdf(ep * d2, 0.0, 1.0))

"""
In []: optionType
Out[]: array(['call', 'put', 'call', ..., 'call', 'call', 'put'], dtype='<U4')

In []: ep
Out[]: array([ 1., -1.,  1., ...,  1.,  1., -1.])

"""


import numpy as np

# FJP: must define Dy as well!!!!!

## FD2 computes the 2nd-order Finite Difference Operator
## ------
#    matrix on N+1 points (i.e. N intervals)
#    D2 = differentiation matrix
#    y  = uniform grid
def FD2(N,L):

    y  = np.linspace(0, L, N+1)       # Meridional coordiante
    dy = y[1] - y[0]                  # grid spacing
    dy2 = dy**2                       # square of dy

    Dyy = np.diag(1/dy2*np.ones(N),-1)   \
        + np.diag(-2/dy2*np.ones(N+1),0) \
        + np.diag(1/dy2*np.ones(N),1)
    Dyy[0,0:3] = np.array([1, -2, 1]/dy2)
    Dyy[N,N-2:N+1] = np.array([1, -2, 1]/dy2)

    return y,Dyy

## CHEB computes the Chebyshev differentiation matrix
## ------
#    matrix on N+1 points (i.e. N intervals)
#    D = differentiation matrix
#    x = Chebyshev grid
def cheb(N):
    if N == 0:
        D = 0
        x = 1
    else:
        x = np.cos(np.pi*np.array(range(0,N+1))/N).reshape([N+1,1])
        c = np.ravel(np.vstack([2, np.ones([N-1,1]), 2])) \
            *(-1)**np.ravel(np.array(range(0,N+1)))
        c = c.reshape(c.shape[0],1)
        X = np.tile(x,(1,N+1))
        dX = X-(X.conj().transpose())
        D  = (c*(1/c).conj().transpose())/(dX+(np.eye(N+1)))   # off-diagonal entries
        D  = D - np.diag(np.sum(D,1))   # diagonal entries
    return D,x
## ------

def Define_Grid(Ny, Ly, method):

    if   method == 'FD2':
        y,D2y = FD2(Ny, Ly)
    elif method == 'cheb':
        Dy,y = cheb(Ny)
        y   = y[:,0] * Ly / 2
        Dy  = Dy * ( 2 / Ly )
        D2y = np.dot(Dy,Dy)
    else:
        print("Method must be either FD2 or cheb")
        sys.exit()

    return y, Dy, D2y


import sympy as sp               # SymPy: The Python computer algebra package upon which NRPy+ depends
import indexedexp as ixp         # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support

thismodule = __name__

# We'll write this as a function so that we can calculate the expressions on-demand for any choice of i
def find_cp_cm(lapse,shifti,gammaUUii):
    # Inputs:  u0,vi,lapse,shift,gammadet,gupii
    # Outputs: cplus,cminus

    # a = 1/(alpha^2)
    a = sp.sympify(1)/(lapse*lapse)
    # b = 2 beta^i / alpha^2
    b = sp.sympify(2) * shifti /(lapse*lapse)
    # c = -g^{ii} + (beta^i)^2 / alpha^2
    c = - gammaUUii + shifti*shifti/(lapse*lapse)

    # Now, we are free to solve the quadratic equation as usual. We take care to avoid passing a
    # negative value to the sqrt function.
    detm = b*b - sp.sympify(4)*a*c

    import Min_Max_and_Piecewise_Expressions as noif
    detm = sp.sqrt(noif.max_noif(sp.sympify(0),detm))
    global cplus,cminus
    cplus  = sp.Rational(1,2)*(-b/a + detm/a)
    cminus = sp.Rational(1,2)*(-b/a - detm/a)

# We'll write this as a function, and call it within HLLE_solver, below.
def find_cmax_cmin(flux_dirn,gamma_faceDD,beta_faceU,alpha_face,gamma_faceUU=None):
    # Inputs:  flux direction flux_dirn, Inverse metric gamma_faceUU, shift beta_faceU,
    #          lapse alpha_face, metric determinant gammadet_face
    # Outputs: maximum and minimum characteristic speeds cmax and cmin
    # First, we need to find the characteristic speeds on each face
    if gamma_faceUU is None:
        gamma_faceUU,unusedgammaDET = ixp.generic_matrix_inverter3x3(gamma_faceDD)
    find_cp_cm(alpha_face,beta_faceU[flux_dirn],gamma_faceUU[flux_dirn][flux_dirn])
    cp = cplus
    cm = cminus

    # The following algorithms have been verified with random floats:

    global cmax,cmin
    # Now, we need to set cmax to the larger of cpr,cpl, and 0

    import Min_Max_and_Piecewise_Expressions as noif
    cmax = noif.max_noif(cp,sp.sympify(0))

    # And then, set cmin to the smaller of cmr,cml, and 0
    cmin = -noif.min_noif(cm,sp.sympify(0))


import numpy as np
from numpy import sqrt, log as ln, linspace
from matplotlib import pyplot as plt
from pprint import pprint

def main():

    def approx_ln(x,n):
        """
            Approximates `ln(x)` using the algorithm described by B.C. Carlsson.\n

            `x`: The value of which to approximate the natural logarithm. Must be greater than 0.

            `n`: The number of iterations for the computations of the algorithm. A greater `n` results in a more accurate approximation.
        """
        # X must be greater than 0, or else the code should not be run.
        if not x < 0:
            # Initialize a value a_0 and g_0 and initialize an error value.
            a = (1+x)/2
            g = sqrt(x)
            # For every step...
            for i in range(1,n+1):

                # Make a_i+1 equal to (a_i + g_i) / 2 and g_i+1 to be sqrt(a_i+1 * g_i)
                next_a = (a + g)/2
                next_g = sqrt(next_a * g)

                # Assign the previously calculated a_i+1/g_i+1 values to be a_i/g_i,
                # so that they will be used in the next iteration.
                a = next_a
                g = next_g

            # Calculate the approximation and return the result and error
            approx = (x-1)/a
            err = abs(approx - ln(x))
            return approx, err

        else:
            # Raise an error if x is not greater than 0.
            raise ValueError("Input must be greater than 0.")

    def fast_approx_ln(x,n):
        """
            Approximates `ln(x)` using the accelerated algorithm described by B.C. Carlsson.\n

            `x`: The value of which to approximate the natural logarithm. Must be greater than 0.

            `n`: The number of iterations for the computations of the algorithm. A greater `n` results in a more accurate approximation.
        """
        if not x < 0:
            def a(x,n):
                # Initialize a_0, g_0
                a = (1+x)/2
                g = sqrt(x)

                for i in range(n):
                    # Make a_i+1 equal to (a_i + g_i) / 2 and g_i+1 to be sqrt(a_i+1 * g_i)
                    next_a = (a+g)/2
                    next_g = sqrt(next_a*g)

                    # Assign the previously calculated a_i+1/g_i+1 values to be a_i/g_i,
                    # so that they will be used in the next iteration.
                    a = next_a
                    g = next_g

                return a

            # For the fast_approx_ln, it is apparent from the description of the method, that it concerns
            # a recursive methods of approximation. Therefore, a function d() is made, that will calculate
            # the value, by calling itself, with k being a value from 1 to n and i from 0 to n.
            def d(x,k,i):
                # Like the method described, for k = 0, we want to simply return a_i.
                if k == 0:
                    return a(x,i)
                # Else, use the formula as decsribed for the accelerated method.
                else:
                    return (d(x,k-1,i)-(4**(-k))*(d(x,k-1,i-1)))/(1-4**(-k))

            # Calculate the approximation and return the result and error
            approx = (x-1)/d(x,n,n)
            err = abs(ln(x) - approx)
            return approx, err

        else:
            # Raise an error if x is not greater than 0.
            raise ValueError("Input must be greater than 0.")

    def task_1():
        """
            Approximates `ln(x)` using the algorithm described by B.C. Carlsson. A greater `n` results in a more accurate approximation.
        """
        # User input
        x = int(input("Please specify what x to approximate ln(x) for: "))
        n = int(input("Please specify a value for n (number of steps for approximation): "))

        # Run the algorithm & print results
        approx, err = approx_ln(x,n)
        print(f"----------------\nResults\n----------------\nApproximating: ln({x})\nIterations: {n}\nApproximation: {approx}\nError: {err}")

    def task_2():
        """
            Plots an approximation of ln(x) using `approx_ln()` against the actual function of ln(x).\n
            A higher `n` results in greater precision.
        """
        # Allow user to specify any values of x and n
        x = int(input("Please specify a range of x for the plot: "))
        n = int(input("Please specify the steps n for the algorithm: "))

        # Make the x axis more detailed by taking 1/10th steps between 0 and x.
        x_axis = linspace(1,x,(x*10))
        # Creating a list of approximation results, with their corresponding error, for every x in the x-axis.
        results = [approx_ln(x,n) for x in x_axis]
        # List of approximations of ln(x) from the previously calculated results.
        y_approx = [r[0] for r in results]
        #  List of ln(x) for every x in the x-axis.
        y_ln = [ln(x) for x in x_axis]

        # Show approx_ln() and ln(x) plotted against the x-axis.
        plt.subplot(1,2,1)
        plt.plot(x_axis, y_approx, label=f"Approx. for ln(x) with n = {n}")
        plt.plot(x_axis, y_ln, label="ln(x)")
        plt.xlabel("x")
        plt.ylabel("ln(x)")
        plt.legend()

        # Create a list of the errors, retrieved from the results list.
        y_err = [r[1] for r in results]

        # Show the error plotted against the x-axis.
        plt.subplot(1,2,2)
        plt.plot(x_axis, y_err, label=f"|approx_ln(x)-ln(x)| with n = {n}")
        plt.xlabel("x")
        plt.ylabel("Error of approximation")
        plt.legend()

        plt.show()

    def task_3():
        """
            Plots the error of approx_ln(1.41,n) against a certain integer n.
        """
        # User input & setting x to 1.41.
        n = int(input("Please specify the steps n for the algorithm: "))
        x = 1.41

        # Let the x-axis be the values of n.
        x_axis = linspace(1,n,n)
        # Create a list of y-values for the error of approx_ln() of x = 1.41
        y_err = [approx_ln(x,i)[1] for i in range(1,n+1)]

        # Show the error of approximation for x = 1.41 plotted against n.
        plt.plot(x_axis, y_err, label="Error of approximation of ln(1.41)")
        plt.xlabel("n number of steps in the algorithm")
        plt.legend()
        plt.show()

    def task_4():
        """
            Approximates `ln(x)` using the accelerated B.C. Carlsson method. A greater `n` results in a more accurate approximation.
        """
        # User input
        x = int(input("Please specify what x to approximate ln(x) for: "))
        n = int(input("Please specify a value for n (number of steps for approximation): "))

        # Run the fast approximation algorithm & print results
        approx, err = fast_approx_ln(x,n)
        print(f"----------------\nResults\n----------------\nApproximating: ln({x})\nIterations: {n}\nApproximation: {approx}\nError: {err}")

    def task_5():
        """
           For the n values 2 to 5, and x from 1 to 20, this function plots
           the error of approximation of `fast_approx_ln(x,n)` on a logarithmic scale.
        """
        # Set a linspace from 1 to 20, with 1/10th steps of detail between every integer of x.
        x = linspace(1,21,200)

        # For 2 to 5 iterations (n), plot the error value of fast_approx_ln(x,n).
        # The x axis is what is being approximated. So one will obtain 4 graphs for
        # n in [2,5] for x values of 1 to 20.
        for n in range(2,6):
            plt.plot(x, [fast_approx_ln(x,n)[1] for x in range(200)], label=f"{n} iterations")

        # Observing the graph in the task description, it is clearly a logarithmic scale on the y-axis.
        plt.yscale("log")

        # Show legend and assign labels/titles, and show the graph.
        plt.legend()
        plt.xlabel("x")
        plt.ylabel("Error")
        plt.title("Error behavior of accelerated Carlsson method for the natural log")
        plt.show()

    # This part of the code will run any individual task based on user input in the terminal.
    run = True
    print('----------------')
    # As long as the program needs to run, keep the while loop running.
    while run:
        query = input("Select task to run or type stop to quit: ")

        if query == 'stop':
            print("----------------\nQuitting program!\n----------------")
            run = False

        # Run one of the 5 tasks based on user input.
        elif query in ['1','2','3','4','5']:
            print(f"----------------\nTask {query} starting\n----------------")
            if query == '1':
                task_1()
            elif query == '2':
                task_2()
            elif query == '3':
                task_3()
            elif query == '4':
                task_4()
            elif query == '5':
                task_5()
            print(f"----------------\nTask {query} finished!\n----------------")
        else:
            print(f"----------------\nInvalid input!\n----------------")

# Run main code
main()


from math import sqrt
import numpy as np

f = open("pb3.txt")  # fac citirea celor 4 puncte din fisier

A = list(map(float, f.readline().split()))  # citesc un rand si convertesc in float folosind map
print("A", A)  # [3.0, 1.0]

B = list(map(float, f.readline().split()))
print("B", B)  # [0.0, 3.0]

C = list(map(float, f.readline().split()))
print("C", C)  # [-3.0, 2.0]

D = list(map(float, f.readline().split()))
print("D", D)  # [-1.0, 0.0]

f.close()

def viraj(a, b, c):
    determinant = b[0] * c[1] + a[0] * b[1] + c[0] * a[1] - a[1] * b[0] - b[1] * c[0] - a[0] * c[1]
    if determinant > 0:
        return 1  # viraj la stanga
    elif determinant < 0:
        return -1  # viraj la dreapta
    else:
        return 0  # coliniare

if viraj(A, B, C) != 1:  # nu e viraj si iau ACB
    tet = np.array([[A[0], A[1], A[0] ** 2 + A[1] ** 2, 1], [C[0], C[1], C[0] ** 2 + C[1] ** 2, 1], [B[0], B[1], B[0] ** 2 + B[1] ** 2, 1], [D[0], D[1], D[0] ** 2 + D[1] ** 2, 1]])
else:  # iau ABC
    tet = np.array([[A[0], A[1], A[0] ** 2 + A[1] ** 2, 1], [B[0], B[1], B[0] ** 2 + B[1] ** 2, 1], [C[0], C[1], C[0] ** 2 + C[1] ** 2, 1], [D[0], D[1], D[0] ** 2 + D[1] ** 2, 1]])
print(tet)
det = np.linalg.det(tet)  # calculez determinantul cu numpy

if det < 0:
    print("D este in <--AFARA--> cercului circumscris triunghiului ABC")  # D = (-6, 0)
elif det == 0:
    print("D este <--PE--> cercul circumscris triunghiului ABC")  # D = (0, 3)
else:
    print("D este <--IN--> cercul circumscris triunghiului ABC")  # D = (-1, 0)

# Incerc si a doua varianta, diferita fata de ideea din curs:

# Calculez pozitia relativa a lui D fata de cercul circumscris triung. ABC

# Vreau sa construiesc punctul de intersectie al mediatoarelor tri. ABC
# Apoi sa fac distanta de la acel punct la D si vad daca e in cerc, pe cerc sau in afara
# Voiam sa iau ecuatiile dreptelor (mediatoarelor) si sa caut punctul de intersectie pentru 2 dintre drepte.
# Am abandonat pentru ca trebuia sa rezolv cu un sistem de ecuatii.

# Am gasit pe wikipedia niste formule.

# Formulele: https://en.wikipedia.org/wiki/Circumscribed_circle#Circumcircle_equations

U = []  # intersectia mediatoarelor
X = 2 * (A[0] * (B[1] - C[1]) + B[0] * (C[1] - A[1]) + C[0] * (A[1] - B[1]))
print("X", X)

U.append(((A[0] ** 2 + A[1] ** 2) * (B[1] - C[1]) + (B[0] ** 2 + B[1] ** 2) * (C[1] - A[1]) + (C[0] ** 2 + C[1] ** 2) * (A[1] - B[1])) / X)
U.append(((A[0] ** 2 + A[1] ** 2) * (C[0] - B[0]) + (B[0] ** 2 + B[1] ** 2) * (A[0] - C[0]) + (C[0] ** 2 + C[1] ** 2) * (B[0] - A[0])) / X)
print("U", U)

# X 18.0
# U [-0.3888888888888889, -0.8333333333333334]

# Acum calculez distanta de la U la D, de la U la C (sau oricare alt punct dintre A,B,C)
# si daca prima distanta e mai mare ca a 2-a atunci
# este in afara, daca este egala atunci este pe cerc, altfel in cerc

UD = sqrt((D[0] - U[0]) ** 2 + (D[1] - U[1]) ** 2)
UC = sqrt((C[0] - U[0]) ** 2 + (C[1] - U[1]) ** 2)
print("UD", UD)
print("UC", UC)

if UD > UC:
    print("D este in <--AFARA--> cercului circumscris triunghiului ABC")  # D = (-6, 0)
elif UD == UC:
    print("D este <--PE--> cercul circumscris triunghiului ABC")  # D = (0, 3)
else:
    print("D este <--IN--> cercul circumscris triunghiului ABC")  # D = (-1, 0)

Algoritmi Avansati (Genetici + Geometrie)/Lab 6/Problema 3.py


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

def triangular(a, b, c):
    def mu(z):
        return np.piecewise(z,
            [((a-b) <= z) & (z < a), (a <= z) & (z <= (a+c)), ((a-b) > z) | (z > (a+c))],
            [lambda z: 1 - (a-z)/b,  lambda z:  1 - (z-a)/c,  lambda z: 0])
    return mu

def sigma(a, b):
    def mu(z):
        return np.piecewise(z,
        [((a-b) <= z) & (z <= a), z > a,       z < (a-b)],
        [lambda z: 1 - (a-z)/b,   lambda z: 1, lambda z: 0])
    return mu

def sigma_inv(a, b):
    def mu(z):
        return np.piecewise(z,
            [(a <= z) & (z <= (a+b)), z < a,       z > (a+b)  ],
            [lambda z: 1 - (z-a)/b,   lambda z: 1, lambda z: 0])
    return mu

def trapezoidal(a,b,c,d):
    def mu(z):
        return np.piecewise(z,
        [((a-c) <= z) & (z < a), (a<= z) & (z < b), (b <= z) & (z <= (b+d)), (z < (a-c)) | (z > (b+d))],
        [lambda z: 1 - (a-z)/c,  lambda z: 1,       lambda z:1 - (z - b)/d , lambda z: 0])
    return mu

def show_membership(features_fuzzy_sets, ranges=None):
    min_, max_ = (0,10) if ranges is None else ranges
    for feature, fuzzy_sets in features_fuzzy_sets.items():
        z = np.linspace(min_, max_, 500)
        plt.title(feature)
        plt.xlabel("z")
        plt.ylabel("$\mu(z)$")
        for fuzzy_set, mu in fuzzy_sets.items():
            plt.plot(z, mu(z), label=fuzzy_set)
        plt.legend()
        plt.show()

def show_fuzzy_set(feature, fuzzy_sets, ranges=None):
    min_, max_ = (0,10) if ranges is None else ranges
    z = np.linspace(min_, max_, 500)
    plt.title(feature)
    plt.xlabel("z")
    plt.ylabel("$\mu(z)$")
    for fuzzy_set, mu in fuzzy_sets.items():
        plt.plot(z, mu(z), label=fuzzy_set)
    plt.legend()
    plt.show()

def build_3_triangular(names, z1, z2, z3):
    if len(names) != 3:
        raise ValueError
    return {
        names[0]: sigma_inv(a=z1, b=z2-z1),
        names[1]: triangular(a=z2, b=z2-z1, c=z3-z2) ,
        names[2]: sigma(a=z3, b=z3-z2)
    }

def build_3_trapezoidal(names, z1, z2, z3, z4):
    if len(names) != 3:
        raise ValueError
    return {
        names[0]: sigma_inv(a=z1, b=z2-z1),
        names[1]: trapezoidal(a=z2, b=z3, c=z2-z1, d=z4-z3) ,
        names[2]: sigma(a=z4, b=z4-z3)
    }

def build_2_sigma(names, z1, z2):
    if len(names) != 2:
        raise ValueError
    return {
        names[0]: sigma_inv(a=z1, b=z2-z1),
        names[1]: sigma(a=z2, b=z2-z1)
    }


import numpy as np

#1. create the array
#list
np1=np.array([1,2,3,4],int)
print(np1,type(np1))
#[1 2 3 4] <class 'numpy.ndarray'>
#tuple
np2=np.array((5,6,7,8),float)
print(np2,type(np2))
#[5. 6. 7. 8.] <class 'numpy.ndarray'>

#2. arrange()
a=np.arange(0,31,2)
print(a)
#[ 0  2  4  6  8 10 12 14 16 18 20 22 24 26 28 30]

#3. linspace()
b=np.linspace(1,15,3)
print(b)
#[ 1.  8. 15.]

#4. zeros() and ones()
c=np.zeros((5,2))
print(c)
#[[0. 0.]
# [0. 0.]
# [0. 0.]
# [0. 0.]
# [0. 0.]]
d=np.ones((3,4))
print(d)
#[[1. 1. 1. 1.]
# [1. 1. 1. 1.]
# [1. 1. 1. 1.]]

#5. construct the N-dimensional matrix
listdata=[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]
e=np.array(listdata)
print(e)
print("維度",e.ndim)
print("形狀",e.shape)
print("數量",e.size)
#[[ 1  2  3  4  5]
# [ 6  7  8  9 10]
# [11 12 13 14 15]]
#維度 2
#形狀 (3, 5)
#數量 15

#6. change the shape of the array reshape()
f=np.arange(1,17)
print(f)
#[ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16]
g=f.reshape(4,4)
print(g)
#[[ 1  2  3  4]
# [ 5  6  7  8]
# [ 9 10 11 12]
# [13 14 15 16]]


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from simple_perceptron import Perceptron
from decision_boundaries import plot_decision_regions
from simple_adaline import AdalineGD

# setup data set
DATAFRAME = pd.read_csv('https://archive.ics.uci.edu/ml/'
                        'machine-learning-databases/iris/iris.data',
                        header=None)
DATAFRAME.tail()

# setup target vec
TARGET_VEC = DATAFRAME.iloc[0:100, 4].values
TARGET_VEC = np.where(TARGET_VEC == 'Iris-setosa', -1, 1)
# setup train matrix
TRAIN_MAT = DATAFRAME.iloc[0:100, [0, 2]].values
# setup and display scatter plot
plt.scatter(TRAIN_MAT[:50, 0], TRAIN_MAT[:50, 1],
            color='red', marker='o', label='setosa')
plt.scatter(TRAIN_MAT[50:100, 0], TRAIN_MAT[50:100, 1],
            color='blue', marker='x', label='versicolor')
plt.xlabel('sepal length')
plt.ylabel('petal length')
plt.legend(loc='upper left')
plt.show()
# train
PERCEP = Perceptron(eta=0.1, n_iter=10)
PERCEP.fit(TRAIN_MAT, TARGET_VEC)
# setup and display number of errors for each epoch
plt.plot(range(1, len(PERCEP.errors) + 1), PERCEP.errors, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of misclassifications')
plt.show()
# plot decision regions for this classification
plot_decision_regions(TRAIN_MAT, TARGET_VEC, classifier=PERCEP)
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upper left')
plt.show()
# setup and display scatter plot for adaline with eta 0.01
_, SUBPLOTS = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))
ADA1 = AdalineGD(n_iter=10, eta=0.01).fit(TRAIN_MAT, TARGET_VEC)
SUBPLOTS[0].plot(range(1, len(ADA1.cost) + 1), np.log10(ADA1.cost), marker='o')
SUBPLOTS[0].set_xlabel('Epochs')
SUBPLOTS[0].set_ylabel('log(Sum-squared-error)')
SUBPLOTS[0].set_title('Adaline - Learning rate 0.01')
# setup and display scatter plot for adaline with eta 0.0001
ADA2 = AdalineGD(n_iter=10, eta=0.0001).fit(TRAIN_MAT, TARGET_VEC)
SUBPLOTS[1].plot(range(1, len(ADA2.cost) + 1), np.log10(ADA2.cost), marker='o')
SUBPLOTS[1].set_xlabel('Epochs')
SUBPLOTS[1].set_ylabel('log(Sum-squared-error)')
SUBPLOTS[1].set_title('Adaline - Learning rate 0.0001')
plt.show()
# implement standardization to transform data into pseudo-normal dist
TRAIN_STD = np.copy(TRAIN_MAT)
TRAIN_STD[:, 0] = (TRAIN_MAT[:, 0] - TRAIN_MAT[:, 0].mean()) / TRAIN_MAT[:, 0].std()
TRAIN_STD[:, 1] = (TRAIN_MAT[:, 1] - TRAIN_MAT[:, 1].mean()) / TRAIN_MAT[:, 1].std()
# retrain adaline with eta 0.01 and standardization so it converges
ADA3 = AdalineGD(n_iter=15, eta=0.01)
ADA3.fit(TRAIN_STD, TARGET_VEC)
# setup and display scatter plot for retrain decision boundaries
plot_decision_regions(TRAIN_STD, TARGET_VEC, classifier=ADA3)
plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal length (standardized)')
plt.ylabel('petal length (standardized)')
plt.legend(loc='upper left')
plt.show()
# setup and display scatter plot for retrain error
plt.plot(range(1, len(ADA3.cost) + 1), ADA3.cost, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.show()
# retrain adaline with stochastic gradient descent (not batch)
ADA4 = AdalineGD(n_iter=15, eta=0.01, rdm_state=1, stochastic=True)
ADA4.fit(TRAIN_STD, TARGET_VEC)
plot_decision_regions(TRAIN_STD, TARGET_VEC, classifier=ADA4)
plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal length (standardized)')
plt.ylabel('petal length (standardized)')
plt.legend(loc='upper left')
plt.show()
# setup and display scatter plot for retrain error
plt.plot(range(1, len(ADA4.cost) + 1), ADA4.cost, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.show()
# model update on individual samples (e.g. online learning)
# ADA4.partial_fit(TRAIN_STD[0, :], TARGET_VEC[0])


#!/usr/bin/env python

import numpy as np
import itertools

def combination(n,m):
    """
    Calculate the combination :math:`C_{n}^{m}`,

    .. math::

        C_{n}^{m} = \\frac{n!}{m!(n-m)!}.

    Parameters
    ----------
    n : int
        Number n.

    m : int
        Number m.

    Returns
    -------
    res : int
        The calculated result.

    Examples
    --------
    >>> combination(6, 2)
    15

    """

    if m>n or n <0 or m <0:
        print("wrong number in combination")
        return
    if m==0 or n==m:
        return 1

    largest = max(m, n-m)
    smallest = min(m, n-m)
    numer = 1.0
    for i in range(largest+1, n+1):
        numer *= i

    denom = 1.0
    for i in range(1,smallest+1):
        denom *= i

    res = int(numer/denom)
    return res

def fock_bin(n, k):
    """
    Return all the possible :math:`n`-length binary where :math:`k` of :math:`n` digitals are set to 1.

    Parameters
    ----------
    n : int
        Binary length :math:`n`.

    k : int
        How many digitals are set to be 1.

    Returns
    -------
    res : list of int-lists
        A list of list containing the binary digitals.

    Examples
    --------
    >>> fock_bin(4, 2)
    [[1, 1, 0, 0],
     [1, 0, 1, 0],
     [1, 0, 0, 1],
     [0, 1, 1, 0],
     [0, 1, 0, 1],
     [0, 0, 1, 1]]

    """

    if n==0:
        return [[0]]

    res = []
    for bits in itertools.combinations(list(range(n)), k):
        s = [0] * n
        for bit in bits:
            s[bit] = 1
        res.append(s)
    return res

def get_fock_bin_by_N(*args):
    """
    Get binary form to represent a Fock state.

    Parameters
    ----------
    args : ints
        args[0]: number of orbitals for 1st-shell,

        args[1]: number of occupancy for 1st-shell,

        args[2]: number of orbitals for 2nd-shell,

        args[3]: number of occupancy for 2nd-shell,

        ...

        args[ :math:`2N-2`]: number of orbitals for :math:`N` th-shell,

        args[ :math:`2N-1`]: number of occupancy for :math:`N` th-shell.

    Returns
    -------
    result : list of int list
        The binary form of Fock states.

    Examples
    --------
    >>> get_fock_bin_by_N(4, 2)
    [[1, 1, 0, 0],
     [1, 0, 1, 0],
     [1, 0, 0, 1],
     [0, 1, 1, 0],
     [0, 1, 0, 1],
     [0, 0, 1, 1]]

    >>> get_fock_bin_by_N(4, 2, 2, 1)
    [[1, 1, 0, 0, 1, 0],
     [1, 0, 1, 0, 1, 0],
     [1, 0, 0, 1, 1, 0],
     [0, 1, 1, 0, 1, 0],
     [0, 1, 0, 1, 1, 0],
     [0, 0, 1, 1, 1, 0],
     [1, 1, 0, 0, 0, 1],
     [1, 0, 1, 0, 0, 1],
     [1, 0, 0, 1, 0, 1],
     [0, 1, 1, 0, 0, 1],
     [0, 1, 0, 1, 0, 1],
     [0, 0, 1, 1, 0, 1]]

    """

    n = len(args)

    if n%2 != 0:
        print("Error: number of arguments is not even")
        return

    if n==2:
        return fock_bin(args[0], args[1])
    else:
        result=[]
        res1 = fock_bin(args[0], args[1])
        res2 = get_fock_bin_by_N(*args[2:])
        for ifock in res2:
            for jfock in res1:
                result.append( jfock + ifock )
        return result

def get_fock_half_N(N):
    res=[[] for i in range(N+1)]
    for i in range(2**N):
        occu = bin(i).count('1')
        res[occu].append(i)
    return res

def get_fock_full_N(norb, N):
    """
    Get the decimal digitals to represent Fock states.

    Parameters
    ----------
    norb : int
        Number of orbitals.

    N : int
        Number of occupancy.

    Returns
    -------
    res : list of int
        The decimal digitals to represent Fock states.

    Examples
    --------
    >>> fock_bin(4,2)
    [[1, 1, 0, 0],
     [1, 0, 1, 0],
     [0, 1, 1, 0],
     [1, 0, 0, 1],
     [0, 1, 0, 1],
     [0, 0, 1, 1]]

    >>> get_fock_full_N(4,2)
    [3, 5, 6, 9, 10, 12]

    """

    res=[]
    half_N = get_fock_half_N(norb//2)
    for m in range(norb//2+1):
        n = N - m
        if n>=0 and n <=norb//2:
            res.extend([i*2**(norb//2) + j for i in half_N[m] for j in half_N[n]])
    return res

def get_fock_basis_by_NLz(norb, N, lz_list):
    """
    Get decimal digitals to represent Fock states, use good quantum number:

    - orbital angular momentum :math:`L_{z}`

    Parameters
    ----------
    norb : int
        Number of orbitals.

    N : int
        Number of total occupancy.

    lz_list : list of int
        Quantum number :math:`l_{z}` for each orbital.

    Returns
    -------
    res : dict
        A dictionary containing the decimal digitals, the key is good quantum numbers :math:`L_{z}`, the value is a list of int.

    Examples
    --------
    >>> get_fock_basis_by_NLz(6, 2, [-1, -1, 0, 0, 1, 1])
    {
     -2: [3],
     -1: [5, 6, 9, 10],
      0: [12, 17, 18, 33, 34],
      1: [20, 36, 24, 40],
      2: [48]
    }
    """

    res = get_fock_basis_by_N_abelian(norb, N, lz_list)
    return res

def get_fock_basis_by_NSz(norb, N, sz_list):
    """
    Get decimal digitals to represent Fock states, use good quantum number:

    - spin angular momentum :math:`S_{z}`

    Parameters
    ----------
    norb : int
        Number of orbitals.

    N : int
        Number of total occupancy.

    sz_list : list of int
        Quantum number :math:`s_{z}` for each orbital.

    Returns
    -------
    res : dict
        A dictionary containing the decimal digitals, the key is good quantum numbers :math:`S_{z}`, the value is a list of int.

    Examples
    --------
    >>> get_fock_basis_by_NSz(6, 2, [1, -1, 1, -1, 1, -1])
    {
     -2: [10, 34, 40],
     -1: [],
      0: [3, 6, 9, 12, 18, 33, 36, 24, 48],
      1: [],
      2: [5, 17, 20]
    }
    """

    res = get_fock_basis_by_N_abelian(norb, N, sz_list)
    return res

def get_fock_basis_by_NJz(norb, N, jz_list):
    """
    Get decimal digitals to represent Fock states, use good quantum number:

    - total angular momentum :math:`J_{z}`

    Parameters
    ----------
    norb : int
        Number of orbitals.

    N : int
        Number of total occupancy.

    jz_list : list of int
        Quantum number :math:`j_{z}` for each orbital.

    Returns
    -------
    res : dict
        A dictionary containing the decimal digitals, the key is good quantum numbers :math:`j_{z}`, the value is a list of int.

    Examples
    --------
    >>> get_fock_basis_by_NJz(6, 2, [-1, 1, -3, -1, 1, 3])
    {
     -6: [],
     -5: [],
     -4: [5, 12],
     -3: [],
     -2: [6, 9, 20],
     -1: [],
      0: [3, 10, 17, 36, 24],
      1: [],
      2: [18, 33, 40],
      3: [],
      4: [34, 48],
      5: [],
      6: []
    }
    """

    res = get_fock_basis_by_N_abelian(norb, N, jz_list)
    return res

def get_fock_basis_by_N_abelian(norb, N, a_list):
    """
    Get decimal digitals to represent Fock states, use some Abelian good quantum number.

    Parameters
    ----------
    norb : int
        Number of orbitals.

    N : int
        Number of total occupancy.

    a_list : list of int
        Quantum number of the Abelian symmetry for each orbital.

    Returns
    -------
    basis : dict
        A dictionary containing the decimal digitals, the key is good quantum numbers, the value is a list of int.
    """

    result=get_fock_full_N(norb, N)
    min_a, max_a = min(a_list)*N, max(a_list)*N
    basis={}
    for i in range(min_a, max_a+1):
        basis[i] = []
    for n in result:
        a=sum([a_list[i] for i in range(0, n.bit_length()) if (n >> i & 1) ])
        basis[a].append(n)
    return basis

def get_fock_basis_by_N_LzSz(norb, N, lz_list, sz_list):
    """
    Get decimal digitals to represent Fock states, use good quantum number:

    - orbital angular momentum :math:`L_{z}`
    - spin angular momentum :math:`S_{z}`

    Parameters
    ----------
    norb : int
        Number of orbitals.

    N : int
        Number of total occupancy.

    lz_list : list of int
        Quantum number :math:`l_{z}` for each orbital.

    sz_list : list of int
        Quantum number :math:`s_{z}` for each orbital.

    Returns
    -------
    basis : dict
        A dictionary containing the decimal digitals, the key is a tuple containing good quantum numbers ( :math:`l_{z}`, :math:`s_{z}`), the value is a list of int.

    Examples
    --------
    >>> get_fock_basis_by_N_LzSz(6, 2, [-1, -1, 0, 0, 1, 1], [1, -1, 1, -1, 1, -1])
    {
     (-2, -2): [],
     (-2, -1): [],
      (-2, 0): [3],
      (-2, 1): [],
      (-2, 2): [],
     (-1, -2): [10],
     (-1, -1): [],
      (-1, 0): [6, 9],
      (-1, 1): [],
      (-1, 2): [5],
      (0, -2): [34],
      (0, -1): [],
       (0, 0): [12, 18, 33],
       (0, 1): [],
       (0, 2): [17],
      (1, -2): [40],
      (1, -1): [],
       (1, 0): [36, 24],
       (1, 1): [],
       (1, 2): [20],
      (2, -2): [],
      (2, -1): [],
       (2, 0): [48],
       (2, 1): [],
       (2, 2): []
    }
    """
    result=get_fock_full_N(norb, N)
    min_Lz, max_Lz = min(lz_list)*N, max(lz_list)*N
    min_Sz, max_Sz = min(sz_list)*N, max(sz_list)*N
    basis={}
    for i in range(min_Lz, max_Lz+1):
        for j in range(min_Sz, max_Sz+1):
            basis[(i,j)] = []
    for n in result:
        Lz, Sz=np.sum([ [ lz_list[i], sz_list[i] ] for i in range(0, n.bit_length()) if (n >> i & 1) ], axis=0)
        basis[(Lz,Sz)].append(n)
    return basis

def write_fock_dec_by_N(N, r, fname='fock_i.in'):
    """
    Get decimal digitals to represent Fock states, sort them by ascending order and then write them to file.

    Parameters
    ----------
    N : int
        Number of orbitals.

    r : int
        Number of occuancy.

    fname : string
        File name.

    Returns
    -------
    ndim : int
        The dimension of the Hilbert space

    Examples
    --------
    >>> write_fock_dec_by_N(4, 2, 'fock_i.in')
    file fock_i.in looks like
    15
    3
    5
    6
    9
    10
    12
    17
    18
    20
    24
    33
    34
    36
    40
    48

    where, the first line is the total numer of Fock states,
    and the following lines are the Fock states in decimal form.
    """

    res=get_fock_full_N(N,r)
    res.sort()
    ndim = len(res)
    f=open(fname, 'w')
    print(ndim, file=f)
    for item in res:
        print(item, file=f)
    f.close()
    return ndim


"""Tests based on the binomial distribution."""

"""
Provides calculations for significance levels for Binomial processes.
A positive (pos) event is the occurrence of something counted.
A negative (neg) event is the non-occurrence. Positive plus negative
events equals the total sample size.
"""

import common_python.constants as cn

import pandas as pd
import numpy as np
import scipy.stats as stats

BINOMIAL_PROB = 0.5

class BinomialDistribution(object):

  def __init__(self, max_count, binomial_prob=BINOMIAL_PROB):
    """
    Parameters
    ----------
    max_count: int
        Maximum value for the number in the binomial population
    binomial_prob: float
    """
    self.max_count = max_count
    self.binomial_prob = binomial_prob
    # Matrix of significance levels for having at least n events
    #   row: sample_size
    #   col: number of events
    # Matrix for positive events
    self.pos_sl_mat = self._populateSignificanceLevels(self.binomial_prob)
    # Matrix for negative events
    self.neg_sl_mat = self._populateSignificanceLevels(1 - self.binomial_prob)

  def _populateSignificanceLevels(self, prob):
    """
    Populates the signifiance level matrices.

    Parameters
    ----------
    prob: float

    Returns
    -------
    matrix
        rows are sample size
        columns are number events
    """
    def calcTailProb(sample_count, nval):
      if nval == 0:
        return 1.0
      return 1 - stats.binom.cdf(nval - 1, sample_count, prob)
    # Initialize the matrix
    size = self.max_count + 1
    mat = np.repeat(np.nan, size*size)
    mat = np.reshape(mat, (size, size))
    #
    for sample_count in range(self.max_count + 1):
      for npos in range(sample_count + 1):
        mat[sample_count, npos] = calcTailProb(sample_count, npos)
    #
    return mat

  def getSL(self, num_sample, num_pos_event, is_two_sided=True):
    """
    Calculates the significance level of obtaining at least num_pos_event's out of
    num_sample. If the test is two sided, then it also calculates
    the significance of num_pos_event's or fewer. In a two sided tests, the
    smaller of the two significance levels is returned. If the smaller one
    is for "too few events", the value is negative.

    Parameters
    ----------
    num_sample: int
    num_pos_event: int
    is_two_sided: bool

    Returns
    -------
    float
    """
    pos_sl = self.pos_sl_mat[num_sample, num_pos_event]
    num_neg_event = num_sample - num_pos_event
    neg_sl = self.neg_sl_mat[num_sample, num_neg_event]
    if pos_sl < neg_sl:
      sl = pos_sl
    else:
      sl = -neg_sl
    return sl

  def isLowSL(self, num_sample, num_event, max_sl, **kwargs):
    """
    Tests if the significance level is no larger than max_sl.

    Parameters
    ----------
    num_sample: int
    num_event: int
    max_sl: float
    kwargs: optional arguments passed to getSL

    Returns
    -------
    bool
    """
    return np.abs(self.getSL(num_sample, num_event, **kwargs)) <= max_sl


#
#  file:  gd_momentum.py
#
#  2D example of gradient descent for a function
#  with more than one minimum with momentum
#
#  RTK, 14-Feb-2021
#  Last update:  21-Feb-2021
#
################################################################

import numpy as np
import matplotlib.pylab as plt

#  Function and partial derivatives
def f(x,y):
    return -2*np.exp(-0.5*((x+1)**2+(y-1)**2)) +  \
           -np.exp(-0.5*((x-1)**2+(y+1)**2))

def dx(x,y):
    return 2*(x+1)*np.exp(-0.5*((x+1)**2+(y-1)**2)) +  \
           (x-1)*np.exp(-0.5*((x-1)**2+(y+1)**2))

def dy(x,y):
    return (y+1)*np.exp(-0.5*((x-1)**2+(y+1)**2)) +  \
           2*(y-1)*np.exp(-0.5*((x+1)**2+(y-1)**2))

#  Gradient descent steps
N = 100
x,y = np.meshgrid(np.linspace(-2,2,N), np.linspace(-2,2,N))
z = f(x,y)
plt.contourf(x,y,z,10, cmap="Greys")
plt.contour(x,y,z,10, colors='k', linewidths=1)
plt.plot([0,0],[-2,2],color='k',linewidth=1)
plt.plot([-2,2],[0,0],color='k',linewidth=1)

def gd(x,y, eta,mu, steps, marker):
    xold = x
    yold = y
    vx = vy = 0.0
    for i in range(steps):
        plt.plot([xold,x],[yold,y], marker=marker, linestyle='dotted', color='k')
        xold = x
        yold = y
        vx = mu*vx - eta * dx(x,y)
        vy = mu*vy - eta * dy(x,y)
        x = x + vx
        y = y + vy

    return x,y

#gd(-1.5, 1.2,20, 'o')
#gd( 1.5,-1.8,40, 's')
#gd( 0.0, 0.0,30, '<')
print("(x,y) = (%0.8f, %0.8f)" % gd( 0.7,-0.2, 0.1,  0.9, 25, '>'))
print("(x,y) = (%0.8f, %0.8f)" % gd( 1.5, 1.5, 0.02, 0.9, 90, '*'))

plt.xlabel("$x$")
plt.ylabel("$y$")
plt.tight_layout(pad=0, w_pad=0, h_pad=0)
plt.savefig("gd_momentum_steps.png", dpi=300)
plt.show()
plt.close()


# Author: Fabrício Olivetti de França

from copy import deepcopy
import numpy as np

from agent import *

def valueIteration(mdp, eps):

    S, A, R, P, gamma = mdp

    # Utilidade inicia começa com tudo 0
    Uprime = { s : 0.0 for s in S }

    # delta inicial é o limite + 1 para entrar no laço
    delta  = eps*(1 - gamma)/gamma + 1.

    while delta > eps*(1 - gamma)/gamma:
        U     = deepcopy(Uprime)
        delta = 0
        for s in S:
            if None in A[s]:
                Uprime[s] = R[s]
            else:
                Uprime[s] = R[s] + gamma * max(expVal(P[(s,a)],U) for a in A[s])
            delta     = max(delta, abs(Uprime[s] - U[s]))

    return U

def policyIteration(mdp):

    S, A, R, P, gamma = mdp

    U       = { s : 0.0 for s in S }
    # política inicial executa a primeira ação da lista
    pi      = { s : A[s][0] for s in S }
    changed = True

    while changed:
        U       = policyEvaluation(pi, U, mdp)
        changed = False
        for s in S:
            # maior valor esperado utilizando a matriz utilidade atual
            maxU = max(expVal(P[(s,a)],U) for a in A[s])
            # maior valor esperado utilizando a política atual
            piU  = expVal(P[(s,pi[s])],U)

            # Se a utilidade ganhar, atualiza a política
            if maxU > piU:
                idx     = np.argmax( [expVal(P[(s,a)],U) for a in A[s]] )
                pi[s]   = A[s][idx]
                changed = True
                #print(s, maxU, piU)
    return pi

def policyEvaluation(pi, U, mdp):
    S, A, R, P, gamma = mdp
    for s in S:
        U[s] = R[s] + gamma * expVal(P[(s, pi[s])],U)
    return U

def expVal(ps, U):
    '''
    retorna o valor esperado da utilidade dadas as probabilidades
    de possíveis estados consequentes armazenados em ps.
    '''
    return sum(p*U[s] for p, s in ps)

def main():
    mdp = createMDP()
    U  = valueIteration(mdp, 1e-3)
    pi = policyIteration(mdp)

    print("Value Iteration: \n")
    for j in range(3,0,-1):
        for i in range(1,5):
            if (i,j) in U:
                print(f"|  {U[(i,j)]:.2f}  |", end="")
            else:
                print("|       |", end="")
        print("")

    print("\n\nPolicy Iteration: \n")
    for j in range(3,0,-1):
        for i in range(1,5):
            if (i,j) in U:
                print(f"|  {pi[(i,j)]}  |", end="")
            else:
                print("|   |", end="")
        print("")

main()


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

N=10**5

n=list(range(1,6))       #slopes of the power law

def I_an(i):             #analytical result of the integral
    i=1/(n[i]+1)
    return i

def f(x,i):              #function to be integrated
    f=x**n[i]
    return f

I_ij=[]                 #matrix i x j where the element I(i,j) is the integral value computed for slope i and with a number of extractions j
for i in range(0, len(n)):
    I_mc=[]
    F=0
    for j in range(0, N):
        x=random.random()
        F+=f(x,i)
        I_mc.append(F/(j+1))
    I_ij.append(I_mc)
I_ij=np.array(I_ij)

y=[30, 50, 100, 300, 500, 1000, 5000, 10000,50000, 90000]       #X axis for the plots
for i in range(0, len(n)):
    plt.figure()
    plt.plot(y, abs(I_an(i)-I_ij[i,y]), 'ro')
    plt.ylabel('$|I_{analytic}-I_{numerical}|$', fontsize=14)
    plt.xlabel('$Number\ of\ extractions\ N$', fontsize=14)
    plt.title('$f(x)= x^{%g}$'%(n[i]))
    plt.xticks(fontsize=10)
    plt.yticks(fontsize=10)
    plt.xscale('log')
    plt.yscale('log')
    plt.ylim(10**(-4),1)
    plt.xlim(10, N)

N=10**4             #number of extractions to compute the integral
k=100               #number of times I compute the integral numerically

mean_n, std_n, N_n=[], [], []     #mean value, standard deviation and number of extractions to obtain an error of 0.001
                                  #relative to the integral, as a funct. of slope

for m in range(0,len(n)):
    int_nm=[]
    for i in range(0,k):
        F=0
        for j in range (0,N):
            x=random.random()
            F+=f(x,m)
        int_nm.append(F/N)
    int_nm=np.array(int_nm)
    mean=np.mean(I_an(m)-int_nm)
    std=np.std(I_an(m)-int_nm)
    mean_n.append(mean)
    std_n.append(std)
    N_n.append(N*(std/0.001)**2)

#print the results as a function of the slope
print('n \t mean \t sigma \t N(sigma < 1e-3)')
for i in range(0,len(n)):
    print('%g \t %.5f \t %.4f \t %.4f'%(n[i], mean_n[i], std_n[i], N_n[i]))


# Percentile
# Description
# Calculate the 60th percentile of the given NumPy array.
# Input: 1D array
# Output: Value of 60th percentile rounded off to two decimal places
# Sample Input 1: [11, 22, 33, 44 ,55 ,66, 77]
# Sample Output 1: 50.6
# Sample Input 2: [-1, 2, 0, 1, 3, 5, 3, 2, 1]
# Sample Output 2: 2.0
import numpy as np
import ast

#input has been taken for you
arr = np.array(ast.literal_eval(input()))
p = round(np.percentile(arr, 60), 2)
print(p)


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

class Plane:
  """
  This class handles graph initialization, general graphing, and plane
  conversions. Some supported planes include rectangular, polar, 2D cartesian,
  and 3D cartesian planes.
  """
  @staticmethod
  def to_rectangular(r, theta, isDegrees=True):
    """
    Converts polar co-ordinate (r, theta) to rectangular co-ordinate (a, b).
    This can then be put into rectangular form (a + bi).
    Formulas:
    - a = r * cos(theta)
    - b = r * sin(theta)
    """
    radians = math.radians(theta) if isDegrees else theta
    a = r * math.cos(radians)
    b = r * math.sin(radians)
    return (a, b)

  @staticmethod
  def to_polar(a, b, isDegrees=True):
    """
    Converts rectangular co-ordinate (a, b) to polar co-ordinate (r, theta).
    Formulas:
    - r = sqrt(x**2+y**2)
    - theta = atan(y/x)
    """
    r = math.sqrt(a**2 + b**2)
    theta = math.atan(b / a)
    # Correct angle for quadrants 3, 2, and 4, respectively
    if a < 0 and b < 0:
      theta = math.pi + abs(theta)
    elif a < 0:
      theta = math.pi - abs(theta)
    elif b < 0:
      theta = 2 * math.pi - abs(theta)
    theta = math.degrees(theta) if isDegrees else theta
    return (r, theta)

  @staticmethod
  def to_quadrant(ref_angle, quadrant, isDegrees=True):
    """Converts a reference angle to an angle in a specified quadrant"""
    # Find the full angle of a circle in either degrees or radians
    full_angle = 360 if isDegrees else (2 * math.pi)
    # Check that the input angle is a reference angle (between 0 and 90 degrees)
    if 0 <= ref_angle < 90:
      if quadrant == 1:
        return ref_angle
      if quadrant == 2:
        return (full_angle / 2) - ref_angle
      if quadrant == 3:
        return (full_angle / 2) + ref_angle
      if quadrant == 4:
        return full_angle - ref_angle

  @staticmethod
  def graph_rectangular(a=None, b=None, scale=1):
    """Plots rectangular co-ordinate on a rectangular plane"""
    Plane.init_cartesian2(plt, scale, x_axis_label='Re', y_axis_label='Im')
    plt.title("Rectangular Graph")
    # 'a' can double-down as a coordinate, in the format (a, b)
    if isinstance(a, tuple):
      b = a[1]
      a = a[0] # this line has to be last, or else 'b' will be assigned to a[0][1]
    plt.scatter(a, b)
    plt.show()

  @staticmethod
  def graph_polar(r=None, theta=None, isDegrees=True):
    """Plots polar co-ordinate on a polar plane"""
    Plane.init_polar(plt, isDegrees=isDegrees)
    # 'r' can double-down as a coordinate, in the format (r, theta)
    if isinstance(r, tuple):
      theta = r[1]
      r = r[0]
    theta = math.radians(theta) if isDegrees else theta
    plt.scatter(theta, r)
    plt.title("Polar Graph")
    plt.show()

  @staticmethod
  def graph_function(function, scale=1):
    """
    Graphs a specified function on a 2D cartesian plane

    *Function argument must be a lambda (ex. `lambda x: x**2`)
    """
    Plane.init_cartesian2(plt, scale)
    x = np.linspace(-scale, scale, 50)
    y = function(x)
    plt.plot(x, y)
    plt.show()

  @staticmethod
  def init_cartesian2(plt, scale, x_axis_label='x', y_axis_label='y'):
    """Creates a formatted 2D cartesian plane."""
    # Setup
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    plt.grid(True)
    # Center axes at origin and remove unnecessary ones
    ax.spines.right.set_visible(False)
    ax.spines.top.set_visible(False)
    ax.spines.left.set_position('center')
    ax.spines.bottom.set_position('center')
    # Set axes limits to scale
    ax.set_aspect('equal')
    ax.set_xlim(-scale, scale)
    ax.set_ylim(-scale, scale)
    # Add black(k) axes arrows that can go outside plot's borders
    # Positioning: xy-coords on stated axis and absolute on perpendicular axis
    ax.plot(1, 0, ">k", transform=ax.get_yaxis_transform(), clip_on=False)
    ax.plot(0, 0, "<k", transform=ax.get_yaxis_transform(), clip_on=False)
    ax.plot(0, 1, "^k", transform=ax.get_xaxis_transform(), clip_on=False)
    ax.plot(0, 0, "vk", transform=ax.get_xaxis_transform(), clip_on=False)
    # Format tick labels to hide the origin and round to 2 decimal places
    hide_origin = lambda x, pos: "" if x == 0 else x
    ax.xaxis.set_major_formatter(ticker.FuncFormatter(hide_origin))
    ax.yaxis.set_major_formatter(ticker.FuncFormatter(hide_origin))
    if type(scale) == float:
      ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:.2f}'))
      ax.yaxis.set_major_formatter(ticker.StrMethodFormatter('{x:.2f}'))
    # Add x and y labels to axes (labelpad moves labels relative to their normal positions)
    ax.set_xlabel(x_axis_label, labelpad=-30, x=1)
    ax.set_ylabel(y_axis_label, labelpad=-33, y=0.98, rotation=0)

  @staticmethod
  def init_cartesian3(plt, scale):
    """Creates a formatted 3D cartesian plane."""
    # Setup
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1, projection='3d')
    # Graph and label xyz axes
    length = scale * 0.75
    ax.quiver(0, 0, 0, length, 0, 0, color='k')
    ax.quiver(0, 0, 0, 0, length, 0, color='k')
    ax.quiver(0, 0, 0, 0, 0, length, color='k')
    ax.text(length, 0, 0, 'x', color='k', fontsize=16)
    ax.text(0, length, 0, 'y', color='k', fontsize=16)
    ax.text(0, 0, length, 'z', color='k', fontsize=16)
    # Set axes limits to scale
    ax.set_xlim(-scale, scale)
    ax.set_ylim(-scale, scale)
    ax.set_zlim(-scale, scale)

  @staticmethod
  def init_polar(plt, isDegrees=True):
    """Creates a formatted polar plane."""
    # Creates a figure and polar plot from matplotlib's base projections
    fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
    if not isDegrees:
      angles = list(ax.get_xticks())
      labels = [str(label / math.pi) + "π" for label in angles]
      ax.set_xticks(ax.get_xticks())
      # Use fixed locators to accurately place fixed-formatted labels (both are lists)
      ax.xaxis.set_major_locator(ticker.FixedLocator(angles))
      ax.set_xticklabels(labels)