#DiamondSquare.py
#Written by Hailey K Buckingham
#On github, buckinha/DiamondSquare
#

import random
import math
import numpy as np

def diamond_square(shape: (int, int),
                   min_height: [float or int],
                   max_height: [float or int],
                   roughness: [float or int],
                   random_seed=None,
                   as_ndarray: bool = True):
    """Runs a diamond square algorithm and returns an array (or list) with the landscape

        An important difference (possibly) between this, and other implementations of the
    diamond square algorithm is how I use the roughness parameter. For each "perturbation"
    I pull a random number from a uniform distribution between min_height and max_height.
    I then take the weighted average between that value, and the average value of the
    "neighbors", whether those be in the diamond or in the square step, as normal. The
    weights used for the weighted sum are (roughness) and (1-roughness) for the random
    number and the average, respectively, where roughness is a float that always falls
    between 0 and 1.
        The roughness value used in each iteration is based on the roughness parameter
    passed in, and is computed as follows:

        this_iteration_roughness = roughness**iteration_number

    where the first iteration has iteration_number = 0. The first roughness value
    actually used (in the very first diamond and square step) is roughness**0 = 1. Thus,
    the values for those first diamond and square step entries will be entirely random.
    This effectively means that I am seeding with A 3x3 grid of random values, rather
    than with just the four corners.
        As the process continues, the weight placed on the random number draw falls from
    the original value of 1, to roughness**1, to roughness**2, and so on, ultimately
    approaching 0. This means that the values of new cells will slowly shift from being
    purely random, to pure averages.

    OTHER NOTES:
    Internally, all heights are between 0 and 1, and are rescaled at the end.

    PARAMETERS
    ----------
    :param shape
        tuple of ints, (int, int): the shape of the resulting landscape

    :param min_height
        Int or Float: The minimum height allowed on the landscape

    :param max_height
        Int or Float: The maximum height allowed on the landscape

    :param roughness
        Float with value between 0 and 1, reflecting how bumpy the landscape should be.
        Values near 1 will result in landscapes that are extremely rough, and have almost no
        cell-to-cell smoothness. Values near zero will result in landscapes that are almost
        perfectly smooth.

        Values above 1.0 will be interpreted as 1.0
        Values below 0.0 will be interpreted as 0.0

    :param random_seed
        Any value. Defaults to None. If a value is given, the algorithm will use it to seed the random
        number generator, ensuring replicability.

    :param as_ndarray
        Bool: whether the landscape should be returned as a numpy array. If set
        to False, the method will return list of lists.

    :returns [list] or nd_array
    """

    # sanitize inputs
    if roughness > 1:
        roughness = 1.0
    if roughness < 0:
        roughness = 0.0

    working_shape, iterations = _get_working_shape_and_iterations(shape)

    # create the array
    diamond_square_array = np.full(working_shape, -1, dtype='float')

    # seed the random number generator
    random.seed(random_seed)

    # seed the corners
    diamond_square_array[0, 0] = random.uniform(0, 1)
    diamond_square_array[working_shape[0] - 1, 0] = random.uniform(0, 1)
    diamond_square_array[0, working_shape[1]-1] = random.uniform(0, 1)
    diamond_square_array[working_shape[0]-1, working_shape[1]-1] = random.uniform(0, 1)

    # do the algorithm
    for i in range(iterations):
        r = math.pow(roughness, i)

        step_size = math.floor((working_shape[0]-1) / math.pow(2, i))

        _diamond_step(diamond_square_array, step_size, r)
        _square_step(diamond_square_array, step_size, r)

    # rescale the array to fit the min and max heights specified
    diamond_square_array = min_height + (diamond_square_array * (max_height - min_height))

    # trim array, if needed
    final_array = diamond_square_array[:shape[0], :shape[1]]

    if as_ndarray:
        return final_array
    else:
        return final_array.tolist()

def _get_working_shape_and_iterations(requested_shape, max_power_of_two=13):
    """Returns the necessary size for a square grid which is usable in a DS algorithm.

    The Diamond Square algorithm requires a grid of size n x n where n = 2**x + 1, for any
    integer value of x greater than two. To accomodate a requested map size other than these
    dimensions, we simply create the next largest n x n grid which can entirely contain the
    requested size, and return a subsection of it.

    This method computes that size.

    PARAMETERS
    ----------
    requested_shape
        A 2D list-like object reflecting the size of grid that is ultimately desired.

    max_power_of_two
        an integer greater than 2, reflecting the maximum size grid that the algorithm can EVER
        attempt to make, even if the requested size is too big. This limits the algorithm to
        sizes that are manageable, unless the user really REALLY wants to have a bigger one.
        The maximum grid size will have an edge of size  (2**max_power_of_two + 1)

    RETURNS
    -------
    An integer of value n, as described above.
    """
    if max_power_of_two < 3:
        max_power_of_two = 3

    largest_edge = max(requested_shape)

    for power in range(1, max_power_of_two+1):
        d = (2**power) + 1
        if largest_edge <= d:
            return (d, d), power

    #failsafe: no values in the dimensions array were allowed, so print a warning and return
    # the maximum size.
    d = 2**max_power_of_two + 1
    print("DiamondSquare Warning: Requested size was too large. Grid of size {0} returned""".format(d))
    return (d, d), max_power_of_two

def _diamond_step(DS_array, step_size, roughness):
    """Does the diamond step for a given iteration.

    During the diamond step, the diagonally adjacent cells are filled:

    Value   None   Value   None   Value  ...

    None   FILLING  None  FILLING  None  ...

    Value   None   Value   None   Value  ...

    ...     ...     ...     ...    ...   ...

    So we'll step with increment step_size over BOTH axes

    """
    # calculate where all the diamond corners are (the ones we'll be filling)
    half_step = math.floor(step_size/2)
    x_steps = range(half_step, DS_array.shape[0], step_size)
    y_steps = x_steps[:]

    for i in x_steps:
        for j in y_steps:
            if DS_array[i,j] == -1.0:
                DS_array[i,j] = _diamond_displace(DS_array, i, j, half_step, roughness)

def _square_step(DS_array, step_size, roughness):
    """Does the square step for a given iteration.

    During the diamond step, the diagonally adjacent cells are filled:

     Value    FILLING    Value    FILLING   Value   ...

    FILLING   DIAMOND   FILLING   DIAMOND  FILLING  ...

     Value    FILLING    Value    FILLING   Value   ...

      ...       ...       ...       ...      ...    ...

    So we'll step with increment step_size over BOTH axes

    """

    # doing this in two steps: the first, where the every other column is skipped
    # and the second, where every other row is skipped. For each, iterations along
    # the half-steps go vertically or horizontally, respectively.

    # set the half-step for the calls to square_displace
    half_step = math.floor(step_size/2)

    # vertical step
    steps_x_vert = range(half_step, DS_array.shape[0], step_size)
    steps_y_vert = range(0, DS_array.shape[1], step_size)

    # horizontal step
    steps_x_horiz = range(0, DS_array.shape[0],   step_size)
    steps_y_horiz = range(half_step, DS_array.shape[1],   step_size)

    for i in steps_x_horiz:
        for j in steps_y_horiz:
            DS_array[i,j] = _square_displace(DS_array, i, j, half_step, roughness)

    for i in steps_x_vert:
        for j in steps_y_vert:
            DS_array[i,j] = _square_displace(DS_array, i, j, half_step, roughness)

def _diamond_displace(DS_array, i, j, half_step, roughness):
    """
    defines the midpoint displacement for the diamond step
    :param DS_array:
    :param i:
    :param j:
    :param half_step:
    :param roughness:
    :return:
    """
    ul = DS_array[i-half_step, j-half_step]
    ur = DS_array[i-half_step, j+half_step]
    ll = DS_array[i+half_step, j-half_step]
    lr = DS_array[i+half_step, j+half_step]

    ave = (ul + ur + ll + lr)/4.0

    rand_val = random.uniform(0,1)

    return (roughness * rand_val) + (1.0 -roughness) * ave

def _square_displace(DS_array, i, j, half_step, roughness):
    """
    Defines the midpoint displacement for the square step

    :param DS_array:
    :param i:
    :param j:
    :param half_step:
    :param roughness:
    :return:
    """
    _sum = 0.0
    divide_by = 4

    # check cell "above"
    if i - half_step >= 0:
        _sum += DS_array[i-half_step, j]
    else:
        divide_by -= 1

    # check cell "below"
    if i + half_step < DS_array.shape[0]:
        _sum += DS_array[i+half_step, j]
    else:
        divide_by -= 1

    # check cell "left"
    if j - half_step >= 0:
        _sum += DS_array[i, j-half_step]
    else:
        divide_by -= 1

    # check cell "right"
    if j + half_step < DS_array.shape[0]:
        _sum += DS_array[i, j+half_step]
    else:
        divide_by -= 1

    ave = _sum / divide_by

    rand_val = random.uniform(0, 1)

    return (roughness * rand_val) + (1.0-roughness) * ave


import numpy as np

def iou_mask(mat_1, mat_2):
    # pass
    intersection = mat_1 * mat_2
    # return intersection
    union = np.clip(mat_1 + mat_2, 0, 1)
    return np.sum(intersection) / np.sum(union)

if __name__ == '__main__':
    mat_1 = np.array([
        [0, 0, 0, 0, 0, 0, 0],
        [0, 1, 1, 1, 0, 0, 0],
        [0, 1, 1, 1, 0, 0, 0],
        [0, 1, 1, 1, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
    ])

    mat_2 = np.array([
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 1, 0, 0, 0],
        [0, 0, 1, 1, 1, 1, 0],
        [0, 0, 0, 1, 1, 1, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
    ])

    print(iou_mask(mat_1, mat_2))


"""
 Function:  x, info = fistaR(fx, gradf, parameter)
 Purpose:   Implementation of fista.
 Parameter: x0         - Initial estimate.
            maxit      - Maximum number of iterations.
            tolx       - Error toleration for stopping condition.
            Lips       - Lipschitz constant for gradient.
            strcnvx    - Strong convexity parameter of f(x).

 Author: Cijo Jose.  [josevancijo@gmail.com]
"""
import time

import numpy as np

def fista(fx, gradf, gx, proxg, parameter, verbose=0):
    x = parameter["x0"]
    y = parameter["x0"]
    t = 1.0
    info = {"itertime": [], "fx": [], "iter": None, "time": None, "totaltime": "None"}
    # Set the clock.
    timestart = time.time()
    # Main loop.
    for iter in range(int(parameter["maxit"])):
        # Compute error and save data to be plotted later on.
        info["itertime"].append(time.time() - timestart)
        fs = fx(x) + gx(x)
        info["fx"].append(fs)
        # Print the information.
        if verbose:
            print("Iter = %4d, f(x) = %5.3e\n" % (iter, info["fx"][iter]))
        # Start the clock.
        fk = 0
        timestart = time.time()
        while True:
            x_next = proxg(y - gradf(y) / parameter["Lips"])
            if fs >= fx(x_next) + gx(x_next) or fk > 0:
                break
            t = 1.0
            y = x
            fk += 1
            # Update the next iteration.
        t_next = 0.5 * (1.0 + np.sqrt(4.0 * t * t + 1.0))
        y = x_next + (t - 1.0) * (x_next - x) / t_next
        # Check stopping criterion.
        if np.linalg.norm(x_next - x) <= parameter["tolx"]:
            break
        x = x_next
        t = t_next
    # Finalization.
    info["iter"] = iter
    info["time"] = np.cumsum(info["itertime"])
    info["totaltime"] = info["time"][iter]
    return x, info

if __name__ == "__main__":
    alpha = 10
    # Parameters for synthetic data.
    cfg = {}
    cfg["n"] = 50
    # number of features
    cfg["p"] = 15
    # number of dimensions
    cfg["noisestd"] = 1e-6
    # standard deviation of additive iid gaussian noise (0 for noiseless)
    # Methods to be checked.
    chk = {
        "GD": True,
        "AGD": True,
        "AGDR": True,
        "LSGD": True,
        "LSAGD": True,
        "LSAGDR": True,
        "CG": True,
    }
    # Generate synthetic data.
    A = np.random.random((cfg["n"], cfg["p"]))
    # Generate s-sparse vector.
    xtrue = np.random.randn(cfg["p"])
    # Take (noisy) samples.
    noise = cfg["noisestd"] * np.random.randn(cfg["n"])
    b = np.dot(A, xtrue) + noise

    fx = lambda x: np.linalg.norm(np.dot(A, x) - b)
    gradf = lambda x: 2 * np.dot(A.T, np.dot(A, x) - b)
    gx_l1 = lambda x: alpha * np.sum(np.abs(x))
    prox_l1 = lambda x: np.max(np.abs(x) - alpha, 0) * np.sign(x)

    parameter = dict()
    parameter["Lips"] = np.linalg.norm(np.dot(A.T, A))
    parameter["x0"] = np.zeros((cfg["p"]))
    parameter["tolx"] = 1e-10  # You can vary tolx and maxit
    parameter["maxit"] = 1e3  # to achieve the convergence.
    x, info = fista(fx, gradf, gx_l1, prox_l1, parameter)


# encoding=utf8

"""Implementations of Dixon Price function."""
import numpy as np

from niapy.problems.problem import Problem

__all__ = ['DixonPrice']

class DixonPrice(Problem):
    r"""Implementations of Dixon Price function.

    Date: 2018

    Author: Klemen Berkovič

    License: MIT

    Function:
    **Dixon Price Function**

        :math:`f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2`

        **Input domain:**
        The function can be defined on any input domain but it is usually
        evaluated on the hypercube :math:`x_i ∈ [-10, 10]`, for all :math:`i = 1, 2,..., D`.

        **Global minimum:**
        :math:`f(\textbf{x}^*) = 0` at :math:`\textbf{x}^* = (2^{-\frac{2^1 - 2}{2^1}}, \cdots , 2^{-\frac{2^i - 2}{2^i}} , \cdots , 2^{-\frac{2^D - 2}{2^D}})`

    LaTeX formats:
        Inline:
            $f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2$

        Equation:
            \begin{equation} f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2 \end{equation}

        Domain:
            $-10 \leq x_i \leq 10$

    Reference:
        https://www.sfu.ca/~ssurjano/dixonpr.html

    """

    def __init__(self, dimension=4, lower=-10.0, upper=10.0, *args, **kwargs):
        r"""Initialize Dixon Price problem..

        Args:
            dimension (Optional[int]): Dimension of the problem.
            lower (Optional[Union[float, Iterable[float]]]): Lower bounds of the problem.
            upper (Optional[Union[float, Iterable[float]]]): Upper bounds of the problem.

        See Also:
            :func:`niapy.problems.Problem.__init__`

        """
        super().__init__(dimension, lower, upper, *args, **kwargs)

    @staticmethod
    def latex_code():
        r"""Return the latex code of the problem.

        Returns:
            str: Latex code.

        """
        return r'''$f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2$'''

    def _evaluate(self, x):
        indices = np.arange(2, self.dimension)
        val = np.sum(indices * (2 * x[2:] ** 2 - x[1:self.dimension - 1]) ** 2)
        return (x[0] - 1) ** 2 + val

# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3


from scipy import stats
import numpy as np
import math
import sys
import json
from collections import OrderedDict
import time
import os

def assertation(lines0):
  run,components,paramdict = json.loads(lines0)
  assert len(run) == paramdict['REPRO_number_of_independent_runs']

def find_t(X1, X2, S1, S2, N1, N2):
  """X1 and X2 are means, S1 and S2 std devs, N1 and N2 are
     population sizes (and not degrees of freedom)
  """
  #with this, the result between scipy and manual is the same
  N1 = N1 - 1
  N2 = N2 - 1
  above = (X1 - X2)
  below = math.sqrt(  ((S1**2)/N1)  +  ((S2**2)/N2)  )
  return above/below

def find_v(S1, S2, N1, N2):
    vx1 = N1-1
    vx2 = N2-1
    above = (  ((S1**2)/N1)  +  ((S2**2)/N2)  )**2
    below = (S1**4)/((N1**2)*vx1)  +  (S2**4)/((N2**2)*vx2)
    return above/below

def scipy_t_test(X1, X2):
    """X1 and X2 are arrays of samples
       returns t,p
    """
    return stats.ttest_ind(X1, X2, equal_var=False)

def manual_t_test(paper_mean, this_mean, paper_std, this_std, paper_runs, this_runs, cmp_dataset_name="expected"):
    """prints stats and returns t,v,p
       The parameter cmp_dataset_name has no effect except label the expected result in the printed output
    """
    print("[manual ttest]")
    error_diff = abs(paper_mean - this_mean)
    insig = False
    if error_diff < 10**(-7):
        insig = True
        pprint = lambda s: print("*{:^72}*".format(s))
        print("*"*(72+2))
        pprint("Difference of error rates < 10^(-7)")
        pprint("the paper treats this as insignificant")
        pprint("(error difference was: {:1.2E})".format(error_diff))
        print("*"*(72+2))

    try:
        t = find_t(X1=paper_mean, X2=this_mean, S1=paper_std, S2=this_std, N1=paper_runs, N2=this_runs)
        v = find_v(S1=paper_std, S2=this_std, N1=paper_runs, N2=this_runs)
        p_value = stats.t.sf(np.abs(t), v)*2 #survival function
    except ZeroDivisionError:
        print("  ZeroDivisionError (paper: {}±{})".format(paper_mean, paper_std))
        print("")
        return -1, -1, -1
    else:
        print("  {tmean:1.4G} ± {tstd:1.4G}    [{pmean:1.4G} ± {pstd:1.4G} <-- {cmp_set}]".format(
                tmean=this_mean,
                tstd=this_std,
                pmean=paper_mean,
                pstd=paper_std,
                cmp_set=cmp_dataset_name))
        print("  t: {t:3.4f}  v: {v:3.4f}".format(t=t,v=v))
        print("  p-value: {p:1.4G}".format(p=p_value))
        print("")
        return t,v,p_value,insig

def write_file_jsonlines(L):
  s = '\n'.join(L)
  filename = str(time.time()).split('.')[0] + '.json_lines'

  path = os.path.join('RESULTS', 'output_json_list', filename)
  if os.path.exists(path):
    print("Filepath '{}' already exists, not overwriting; printing instead:".format(path))
    print(s)
  else:
    print("Writing final jsonlines-output to '{}'".format(path))
    with open(path,'w') as f:
      f.write(s)

def compare_with_paper(runfile):
  with open(runfile) as f:
    lines = [x.strip() for x in f.readlines()]

  json_lines_output = []

  for line in lines:
    assertation(line)
    runs,components,paramdict = json.loads(line)

    paper_mean = paramdict['PAPER_mean_error']
    paper_std = paramdict['PAPER_std_dev']
    this_mean = np.mean(runs)
    this_std = np.std(runs)

    paper_runs = paramdict['PAPER_number_of_independent_runs']
    this_runs = paramdict['REPRO_number_of_independent_runs']

    t,v,p,insig = manual_t_test(paper_mean=paper_mean,
                                paper_std=paper_std,
                                paper_runs=paper_runs,
                                this_mean=this_mean,
                                this_std=this_std,
                                this_runs=this_runs,
                                cmp_dataset_name="paper_results")
    print('\n')

    #dump the results to one final file
    newdict = OrderedDict()
    newdict['stat_runs'] = runs
    newdict['stat_components'] = components
    newdict['stat_t'] = t
    newdict['stat_v'] = v
    newdict['stat_p'] = p
    newdict['stat_insignificant_error_diff'] = insig
    newdict['REPRO_mean_error'] = this_mean
    newdict['REPRO_std_dev'] = this_std
    for key in sorted(paramdict):
      newdict[key] = paramdict[key]
    json_lines_output.append(json.dumps(newdict))
  write_file_jsonlines(json_lines_output)

def compare_two_runs(runfile1, runfile2):
  with open(runfile1) as f:
    lines1 = [x.strip() for x in f.readlines()]
  with open(runfile2) as f:
    lines2 = [x.strip() for x in f.readlines()]

  for line1,line2 in zip(lines1,lines2):
    assertation(line1)
    assertation(line2)
    run1,components1,paramdict1 = json.loads(line1)
    run2,components2,paramdict2 = json.loads(line2)

    print('Params1:', paramdict1)
    if paramdict2 != paramdict1:
      print('Params2:', paramdict2)
    else:
      print('Params2: <same as above>')

    t,p = scipy_t_test(run1, run2)
    print("[scipy ttest]\n  t: {t:3.4f}    p: {p:1.4G}".format(t=t,p=p))

    # treat run1 as the paper and run2 as the reproduction attempt
    # this is to investigate the implementation of the t-test and how
    # it performs on two populations generated the same way
    manual_t_test(paper_mean=np.mean(run1),
                  this_mean=np.mean(run2),
                  paper_std=np.std(run1),
                  this_std=np.std(run2),
                  paper_runs=len(run1),
                  this_runs=len(run2),
                  cmp_dataset_name=runfile1)

    print('\n\n\n')

if __name__ == '__main__':
  if len(sys.argv) == 2:
    runfile = sys.argv[1]
    print("Comparing a run to the results from the paper")
    print("File: {}\n".format(runfile))
    compare_with_paper(runfile)

  elif len(sys.argv) == 3:
    runfile1, runfile2 = sys.argv[1], sys.argv[2]
    print("Comparing two runs made using the same implementation")
    print("Files: {}  {}\n".format(runfile1, runfile2))
    compare_two_runs(runfile1, runfile2)
  else:
    print("Usage:")
    print("  Compare own run to paper results (and also write a final result-file):")
    print("    python3 t_test.py dumps/runfile_produced_by_main_invocation.run")
    print("")
    print("  Compare two own runs:")
    print("    python3 t_test.py dumps/runfile1_produced_by_1st_main_invocation.run dumps/runfile2_produced_by_2nd_main_invocation.run")


import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-3,3,1000)
print(x)

relu = lambda x: max(0.0,x)

y = np.zeros_like(x)
for i in range(len(x)):
    y[i] = relu(x[i])

sig = 1/(1 + np.exp(-x))

fig,ax = plt.subplots(1,2)

ax[0].plot(x,y)
ax[1].plot(x,sig)
plt.grid('on')
plt.show()

import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
sigmoid = np.vectorize(sigmoid) #vectorize function
values=np.linspace(-10, 10) #generate values between -10 and 10
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

#spine placement data centered
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0.0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

plt.plot(values, sigmoid(values), color=(1,0.25,0))
plt.show()

import numpy as np
import matplotlib.pyplot as plt
def relu(x):
    y = np.zeros_like(x)
    for i in range(len(x)):
        y[i] = max(0.0, x[i])
    return y

values=np.linspace(-10, 10, 1000) #generate values between -10 and 10
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

#spine placement data centered
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0.0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

plt.plot(values, relu(values), color=(1,0.25,0))
plt.show()


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

import numpy as np
import numpy.linalg as la
import numpy.polynomial.polynomial as poly
import matplotlib.pyplot as plt

data = np.loadtxt("whData.dat", dtype=np.object, comments='#',  delimiter=None)
#removing outliers or data with weight -1
data = data[ data[:,0] != '-1' , : ]

hgt = data[:,1].astype( np.float)
wgt = data[:,0].astype( np.float)

xmin = hgt.min()-15
xmax = hgt.max()+15
ymin = wgt.min()-15
ymax = wgt.max()+15

def plot_data_and_fit(h, w, x, y, figname):
    plt.plot(h, w, 'ko', x, y, 'r-')
    plt.xlabel('Height')
    plt.ylabel('Weight')
    plt.xlim(xmin,xmax)
    plt.ylim(ymin,ymax)
    plt.savefig("{}.pdf".format(figname), facecolor='w', edgecolor='w',
                 orientation='potrait', format='pdf', transparent=False)
    plt.show()
def trsf(x):
    return x / 100.

n = 10
x = np.linspace(xmin, xmax, 100)

# method 1:
# regression using polyfit
c = poly.polyfit(hgt, wgt, n)
y = poly.polyval(x, c)
plot_data_and_fit(hgt, wgt, x, y, "polyfit")

# method 2:
# regression using the Vandermonde matrix and pinv
X = poly.polyvander(hgt, n)
#Pattern Recognition (1) B-IT, Summer Term 2019
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(x,n), c)
plot_data_and_fit(hgt, wgt, x, y, "method2")

# method 3:
# regression using the Vandermonde matrix and lstsq
X = poly.polyvander(hgt, n)
c = la.lstsq(X, wgt)[0]
y = np.dot(poly.polyvander(x,n), c)
plot_data_and_fit(hgt, wgt, x, y, "method3")

# method 4:
# regression on transformed data using the Vandermonde
# matrix and either pinv or lstsq
X = poly.polyvander(trsf(hgt), n)
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(trsf(x),n), c)
plot_data_and_fit(hgt, wgt, x, y, "method4")


import numpy as np
import nanalysis as na
import support
from support import BaseFunction, get_base_args
import matplotlib.pyplot as plt

#m: Malthus 係数
class Exponential( BaseFunction ):
	def __init__( self, m = 3 ):
		self.m = m
		self.numberofvalues = 1
	def get_values( self, x, t ):
		return self.m * x

class Logistic( BaseFunction ):
	def __init__(self,  r = 1, K = 100 ):
			self.r = r
			self.K = K
			self.numberofvalues = 1
	def get_values( self, x, t ):
		return self.r * x * ( 1 - x / self.K )

	def get_linelist( self ):
		return [ [ 0, self.K ] ]

class Alley( BaseFunction ):
	def __init__( self, r = 0.03, K = 100, a = 20):
		self.r = r
		self.K = K
		self.a = a
		self.numberofvalues = 1

	def get_values( self, x, t ):
		return self.r * x * ( 1 - x / self.K ) * ( x - self.a )

	def get_linelist( self ):
		return [ [ 0, self.K ], [ 0, self.a ] ]

class Yamamura( BaseFunction ):

	def	__init__( P = 10 , r = 1.0, K = 100.0 ):
		self.P = P
		self.r = r
		self.K = K
		self.numberofvalues = 1
	def get_values( self, x, t ):
		return self.r * x *( 1 - x /self.K ) - self.P * x**2 / ( 1 + x**2 )

if __name__ == '__main__':

	ps = get_base_args()
	args = ps.parse_args()
	graph_n = args.equation_number
	ad = args.argdict
	sp   = args.spoint
	ep   = args.epoint
	hl   = args.hline
	vl   = args.vline
	llist  =  args.line
	pp   =  args.pointplot
	initial_value = args.initial_value
	saveoff = support.offsaving( args.savefigoff )

	graph = { 1: Exponential, 2: Logistic, 6: Alley, 4: Yamamura }

	if ad:
		function = graph[ graph_n ](**ad)
	else:
		function = graph[ graph_n ]()

	linelist =  function.get_linelist()

	if llist:
		linelist.append(llist)

	initial_value = np.array( initial_value ).reshape( -1, )

	t,xpoints, ypoints, zpoints = function.get_values_rungekutta( sp = sp, ep = ep, initial_value = initial_value, numberofvalues = function.numberofvalues )

	adplots = None

	if 'get_additionalplots' in dir(function ):
		adplots = function.get_additionalplots()

	na.graph_plot( t, xpoints = xpoints, ypoints = ypoints, zpoints = zpoints, chapter = 3 , function = function, hlines = hl, vlines = vl, linelist = linelist , savefigOn = saveoff, graph_n = graph_n, N = 1000, pointplot = pp, ntimegraphs = len( initial_value), additionalplots = adplots )


#codes are seperated by """ as multiline comments

"""
# Importing important libraries
import numpy as np
fromscipy.stats import norm

# Defining the methods required
def mean(n1, n2, n):
return ((2*n1*n2)/n)+1

def variance(n1,n2,n):
returnnp.sqrt((2*n1*n2*(2*n1*n2-n))/(n**2*(n-1)))

def statistic(r, mean, variance):
    return (r-mean)/variance

# Calculating Mean and Variance
m = mean(19,26,45)
print("Mean is: ", m)

v = variance(19,26,45)
print("Variance is: ", v)
"""

"""
z_statistic = statistic(19,m,v)
print("Z-Statistic is: ", z_statistic)

# define level of significance
a = 0.05

# Getting Critical Value
value = norm.ppf(1-a)

print("Z-Critical is: ", value)

if z_statistic>value:
print("Reject Null Hypothesis")
else:
print("Accept Null Hypothesis")
"""

"""
before = [18.5,21.5,21,20,15,19.75,15.75,18,22,15,20.5]
after = [19.25,21.75,20.25,22.25,16,19.5,17,19.25,19.5,16.5,20]

fromscipy.stats import wilcoxon

t, p = wilcoxon(after, before)

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")
"""

"""
Lincoln_Calcium = [0.11, 0.41, 0.19, 0.33, 0.09, 0.33, 0.67, 0.20, 0.21, 0.20, 0.75, 0.42, 0.09, 0.22,
                   0.19, 0.25, 0.07, 0.34, 0.30, 0.47, 0.30, 0.46]

Clarendon_Calcium = [0.06, 0.12, 0.14, 0.10,0.09, 0.29, 0.14, 0.21,0.14, 0.10, 0.12, 0.16,0.16, 0.41,
                     0.08, 0.13,0.03, 0.08, 0.09, 0.12]

fromscipy.stats import mannwhitneyu

t, p = mannwhitneyu(Lincoln_Calcium, Clarendon_Calcium,alternative='two-sided')

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")
"""

"""
personal_income = [48285,39817,66000,43874,32219,34453,31799,33786,37780]
birth_rate = [13.9,14.1,15.1,14.1,12.1,14.5,14.3,15.8,13.1]

fromscipy.stats import spearmanr

t, p = spearmanr(personal_income, birth_rate)

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")

"""

"""
period_A = [10456,11574,12321,11661,8521,11621,11321,7706,10872,10837]
period_B = [10799,11743,11657,11608,10982,9184,12357,12251,11916,11212]
period_C = [11465,12475,12454,12193,11244,12081,11387,9055,12319,12927]
period_D = [11261,11406,11627,8706,12022,11930,11054,11431,12618,10824]

fromscipy.stats import kruskal

t, p = kruskal(period_A,period_B,period_C,period_D)

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")
"""


'''
This fun project and playing with primes was insprired by 3Blue1Brown's video on youtube.

3Blue1Brown is a brilliant youtube channel on mathematics
Here is the link for the video: https://www.youtube.com/watch?v=EK32jo7i5LQ

This code replicates the distribution of prime numbers plot in a polar co-ordinate system seen in the video.
You can plot the first n prime numbers. Here there is only one input defined by the variable num.

'''

import math
import matplotlib.pyplot as plt
import numpy as np
from numba import jit
import time

@jit(nopython=True)
def is_prime(num):
    '''
    This function checks if any number is a prime number
    '''
    if num < 2:
        return False
    if num % 2 == 0 and num > 2:
        return False
    for i in range(3, int(math.sqrt(num)) + 1, 2):
        if num % i == 0:
            return False
    return True

@jit(nopython=True)
def nth_prime(n):
    '''
    This function generates the first n prime number where is defined by the user.
    n can change by assigning any positive integer to the variable num below
    '''
    i = 1
    j = 0
    list_of_primes = []
    while j < n:
        if is_prime(i):
            list_of_primes.append(i)
            j += 1
        i += 1
        #print(j, end='\r')
    return list_of_primes

## Running the functions here
num = 500000##-----> INPUT HERE

tic = time.perf_counter()
primes = nth_prime(num)
toc = time.perf_counter()

time = abs(toc - tic)

print('\n',time)
n = len(primes)

## Visualization
f = plt.figure(figsize=(10,10))
plt.subplot(111,polar = True)
ax1 = plt.scatter(primes,primes, s = 0.001)
plt.title(str(n)+' Primes', fontsize=36)
plt.axis('off')
plt.show()

f.savefig('{}_primes.png'.format(num),format='PNG',dpi=800)


import numpy as np
import matplotlib.pyplot as plt
from gradient_descent import gradient_descent
from examples import ex1, ex2, conditioned_quadratic
from plotutils import PlaneIterationPlotter
import seaborn as sns
sns.set_context("talk")

fun = conditioned_quadratic(cond=10)

starting_point = np.ones((2,1)) / np.sqrt(2)

condition_numbers = [1, 2, 4, 8, 16, 32, 64, 128]

for number in condition_numbers:
    fun = conditioned_quadratic(cond=number)

    plotter = PlaneIterationPlotter(fun, xlim=(-1,1), ylim=(-1,1))
    descents, _, _ = gradient_descent(fun, starting_point, tolerance=1e-10)

    plotter.plot_contours(colors=plt.cm.Greys(np.linspace(0,5)))
    plotter.plot_points(descents, 'ro')
    plotter.ax.set_title(f'Gradient Descent on Quadratic Form with $\kappa={number}$')
    plotter.save(f'figures/gd-condition-number-{number}.png', bbox_inches='tight')


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

# This script describes the interaction of economic growth rate, government budget
# deficit and the size of government debt. It is also described in the accompanying
# iPython Notebook and at
#
# http://misunderheard.org/blog/2015/07/14/what-is-a-sustainable-government-deficit/
#

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

#%% Create function which simulates economics scenario and plots course of government debt

def run_economy(time_steps, growth_rate, deficit_rate, start_income, start_debt):

    # Calculate the rate constant for economy growth based on passed in growth rate
    growth_rate_constant = (np.log(1 + growth_rate))

    # Initialize a list of timestep indices, e.g. 0, 1, 2, 3,...
    # This will be used to solve each of the equations through this number of timesteps
    # Since we're using the numpy library we can simply pass this vector of timesteps into
    # the equations and get a vector of solutions
    time_vector = np.linspace(0,time_steps-1,time_steps)

    # Calculate incomes (i.e. GDP with growth) across all timesteps
    income = start_income * np.exp(growth_rate_constant * time_vector)

    # Calculate debt across all timesteps
    debt   = start_debt + (deficit_rate * start_income / growth_rate_constant) * (np.exp(growth_rate_constant * time_vector) - 1)

    # Calculate the debt ratio across all timesteps
    # We could just divide the debt and income variables at this stage but lets use the elegant form!
    debt_ratio = (deficit_rate / growth_rate_constant) + ((start_debt / start_income) - (deficit_rate / growth_rate_constant))*np.exp(-(growth_rate_constant * time_vector))

    # Now plot all
    fig = plt.figure()

    gdp_plot = fig.add_subplot(311, xlim=(0, time_steps), ylim=(0, np.max(income)))
    gdp_plot.grid()
    gdp_plot.plot(range(time_steps),income)
    plt.ylabel('GDP')

    debt_plot = fig.add_subplot(312, xlim=(0, time_steps), ylim=(0, np.max(debt)))
    debt_plot.grid()
    debt_plot.plot(range(time_steps),debt)
    plt.ylabel('Debt')

    debt_ratio_plot = fig.add_subplot(313, xlim=(0, time_steps), ylim=(0, np.max(debt_ratio)))
    debt_ratio_plot.grid()
    debt_ratio_plot.plot(range(time_steps),debt_ratio)
    plt.ylabel('Debt/GDP')
    plt.xlabel('Time (arbitrary)')

    fig.show()

#%% Run some scenarios

run_economy(200, 0.02, 0.01, 500.0, 500.0)

run_economy(200, 0.02, 0.01, 500.0, 0.0)

run_economy(200, 0.02, 0.02, 500.0, 50.0)


import numpy as np
import pylab
import cv2
pylab.ion()

def kernal_convolution(image_path):

    '''
    *Performs a Sobel Kernal Conolution and Saves Output as jpg.

	Parameters
	----------

	image_path : <type 'str'>
		Path and file name of image (jpg or png)

	Returns
	-------
	y_copy :  <type 'ndarray'>
    '''

    #Sobel kernal
    kernal_x = [[-1,0,1],
               [-2,0,2],
               [-1,0,1]]

    kernal_y = [[-1,-2,-1],
               [0,0,0],
               [1,2,1]]

    #open image and make copy
    img = cv2.imread(image_path)
    y = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    xsize,ysize = y.shape
    y_copy = np.zeros((xsize,ysize))

    #loop through and calculate
    for i in range(1, xsize-1):

        for j in range(1, ysize - 1):

            xpix = (kernal_x[0][0] * y[i-1][j-1]) + (kernal_x[0][1] * y[i][j-1]) + (kernal_x[0][2] * y[i+1][j-1]) +\
                (kernal_x[1][0] * y[i-1][j])   + (kernal_x[1][1] * y[i][j])   + (kernal_x[1][2] * y[i+1][j]) +\
                (kernal_x[2][0] * y[i-1][j+1]) + (kernal_x[2][1] * y[i][j+1]) + (kernal_x[2][2] * y[i+1][j+1])

            ypix = (kernal_y[0][0] * y[i-1][j-1]) + (kernal_y[0][1] * y[i][j-1]) + (kernal_y[0][2] * y[i+1][j-1]) +\
                (kernal_y[1][0] * y[i-1][j])   + (kernal_y[1][1] * y[i][j])   + (kernal_y[1][2] * y[i+1][j]) +\
                (kernal_y[2][0] * y[i-1][j+1]) + (kernal_y[2][1] * y[i][j+1]) + (kernal_y[2][2] * y[i+1][j+1])

            mag = np.sqrt( (xpix * xpix) + (ypix * ypix) )
            mag = np.abs(mag)

            y_copy[i][j] = mag

    #normalise and save
    y_copy *= 255.0 / np.max(y_copy)
    pylab.imshow(y_copy, cmap = 'gray')
    pylab.savefig('output_' + image_path + '.jpg', dpi=200)

    return y_copy

if __name__ == '__main__':

    #example file 'corpus.jpg'
    arr = kernal_convolution('corpus.jpg')


"""
Ajay Kc
013213328
EE381
Project 6 Part 2
The experiment deals with five state Markov Chain where theoretical probability is plotted and the probability of each
page being visited is calculated.
"""
import numpy as np
import matplotlib.pyplot as plt

step = 20
transition_matrix = [[0,1,0,0,0],
                     [1/2,0,1/2,0,0],
                     [1/3,1/3,0,0,1/3],
                     [1,0,0,0,0],
                     [0,1/3,1/3,1/3,0]]
v1 = [1/5,1/5,1/5,1/5,1/5]
v2 = [0,0,0,0,1]
theoretical_probability_one = np.zeros((step+1,5))
theoretical_probability_two = np.zeros((step+1,5))
theoretical_probability_one[0,:]=v1
theoretical_probability_two[0,:]=v2

def calculate_theoretical_probabilities():
    for i in range(step):
        theoretical_probability_one[i+1,:]=np.matmul(theoretical_probability_one[i,:],transition_matrix)
        theoretical_probability_two[i + 1, :] = np.matmul(theoretical_probability_two[i, :], transition_matrix)

def plotGraph(state_one,state_two,state_three,state_four,state_five,xlabel,ylabel,title):

    plt.xlabel(xlabel, fontsize=20)
    plt.ylabel(ylabel, fontsize=20)
    plt.title(title, fontsize=20)

    plt.figure(1)
    plt.plot(range(0,step+1),state_one,color='b',marker='d',linestyle='--', label='State A')
    plt.plot(range(0, step + 1), state_two, color='r', marker='H', linestyle='--', label='State B')
    plt.plot(range(0, step + 1), state_three, color='g', marker='^', linestyle='--', label='State C')
    plt.plot(range(0, step + 1), state_four, color='m', marker='*', linestyle='--', label='State D')
    plt.plot(range(0, step + 1), state_five, color='y', marker='p', linestyle='--', label='State E')
    plt.legend(loc='best')

    plt.show()

calculate_theoretical_probabilities()

plotGraph(theoretical_probability_one[:,0],theoretical_probability_one[:,1],theoretical_probability_one[:,2],
          theoretical_probability_one[:, 3],theoretical_probability_one[:,4],"Step Number","Probability",
          "Five state Markov Chain - Calculated Using the State Transition Matrix where each state has equal initial probability")

plotGraph(theoretical_probability_two[:,0],theoretical_probability_two[:,1],theoretical_probability_two[:,2],
          theoretical_probability_two[:, 3],theoretical_probability_two[:,4],"Step Number","Probability",
          "Five state Markov Chain - Calculated Using the State Transition Matrix where one site is the home page")


# Libraries
import numpy as np
import matplotlib.pyplot as plt

# Coordinate matrix
# number of nodes
nnos = 11
# number of elements
nel  = nnos - 2

# coordinate matrix pre-allocation
coord = np.zeros((nnos, 3))
coord[0][0] = 1

# theta value
theta = (np.pi/2)/(nnos-2)

for i in range(0, nnos-1):
    coord[i + 1][0] = i + 2             # Node reference
    coord[i + 1][1] = np.cos(theta*i)   # X coordinate
    coord[i + 1][2] = np.sin(theta*i)   # Y coordinate

# Plot
fig = plt.figure()
plt.xlim([0,1])
plt.ylim([0,1])
plt.scatter(coord[:,1], coord[:,2], marker = '+', c = 'black', alpha = 0.85)
plt.xlabel('x', fontsize = 'xx-large')
plt.ylabel('y', fontsize = 'xx-large')

# Incidence matrix
# incidence matrix pre-allocation
inci = np.zeros((nel, 3))

for i in range(0,nel):
    # central node
    inci[i][0] = 1
    # first node
    inci[i][1] = i + 2
    # second node
    inci[i][2] = i + 3

fig, ax = plt.subplots()
plt.xlim([0,1])
plt.ylim([0,1])

for i in range(0,nel):
    node1 = inci[i][0]
    node2 = inci[i][1]
    node3 = inci[i][2]

    x1 = coord[int(node1) - 1][1]
    x2 = coord[int(node2) - 1][1]
    x3 = coord[int(node3) - 1][1]
    x  = np.array([x1, x2, x3])

    y1 = coord[int(node1) - 1][2]
    y2 = coord[int(node2) - 1][2]
    y3 = coord[int(node3) - 1][2]
    y  = np.array([y1, y2, y3])
    if i%2 == 0:
        ax.fill(x, y,'k',alpha=0.3)
    else:
        ax.fill(x, y,'b',alpha=0.3)

# Area
# somatory
A = 0

# central node coordinates
x1 = coord[int(inci[0,0] - 1), 1]
y1 = coord[int(inci[0,0] - 1), 2]

f = np.zeros(nnos-1)

for i in range(0,nel):
    #     second node coordinates
    x2 = coord[int(inci[i,1] - 1), 1]
    y2 = coord[int(inci[i,1] - 1), 2]

    #     third node coordinates
    x3 = coord[int(inci[i,2] - 1), 1]
    y3 = coord[int(inci[i,2] - 1), 2]

    a = 0.5*((x2 - x1)*(y3-y1) - (x3 - x1)*(y2 - y1))

    f[i] = a

    #     area summation
    A += a

# relative error
error_Area = (np.pi/4 - A)/(np.pi/4)*100
# display('Error = ',error_Area)

print('Error = ', error_Area,'%')

# Centroid
centx = 0
centy = 0

for i in range(0,nel):
    #     second node coordinates
    x2 = coord[int(inci[i,1] - 1), 1]
    y2 = coord[int(inci[i,1] - 1), 2]

    #     third node coordinates
    x3 = coord[int(inci[i,2] - 1), 1]
    y3 = coord[int(inci[i,2] - 1), 2]

    centx = centx + a*((x1+x2+x3)/3)
    centy = centy + a*((y1+y2+y3)/3)

# centroid X
X = centx/A

# centroid Y
Y = centy/A

# exact centroid
exact_cent = 4/(np.pi*3)

# error X
error_x = (exact_cent - X)/exact_cent*100
# error Y
error_y = (exact_cent - Y)/exact_cent*100

print('Error centroid X = ', error_x,'%')
print('Error centroid Y = ', error_y,'%')

# Inertia moment
Ix = 0
Iy = 0

# central node coordinates
x1 = coord[int(inci[0,0] - 1), 1]
y1 = coord[int(inci[0,0] - 1), 2]

for i in range(0,nel):
    #     second node coordinates
    x2 = coord[int(inci[i,1] - 1), 1]
    y2 = coord[int(inci[i,1] - 1), 2]

    #     third node coordinates
    x3 = coord[int(inci[i,2] - 1), 1]
    y3 = coord[int(inci[i,2] - 1), 2]

    Ix += 1/12*(y1**2+y2**2+y3**2+y1*y2+y1*y3+y2*y3)*(x2*y3-x3*y2) # momento de inércia em relação ao eixo x
    Iy += 1/12*(x1**2+x1*x2+x1*x3+x2**2+x2*x3+x3**2)*(x2*y3-x3*y2) # momento de inércia em relação ao eixo x

Iexato = np.pi/16 # valor exato do momento de inércia do quarto de círculo para R = 1

erro_Ix = (Iexato-Ix)/Iexato*100
erro_Iy = (Iexato-Iy)/Iexato*100

print('Error inertia X = ', erro_Ix,'%')
print('Error inertia Y = ', erro_Iy,'%')


import sympy
from sympy.plotting import plot_implicit
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

def mid_value(interval): return interval.mid

class Heart01:

    def __init__(self):
        self.x, self.y, self.a = sympy.symbols('x, y, a')
        self.eq = sympy.Eq((self.x**2 + self.y**2 - self.a)
                           ** 3 - self.x**2 * self.y**3, 0)
        self.fig, self.ax = self.plot_setup()

    def plot_setup(self):
        fig, ax = plt.subplots(figsize=(8, 8))
        ax.grid(False)
        ax.set_axis_off()
        return fig, ax

    def animate(self, constant):

        e = self.eq.subs({self.a: constant})
        p = plot_implicit(e, show=False)

        intervals = np.array(p[0].get_points()[0])
        px = tuple(map(mid_value, intervals[:, 0]))
        py = tuple(map(mid_value, intervals[:, 1]))
        points = np.array((px, py))

        heart = self.ax.scatter(*points)
        return heart,

    def show(self, frames=range(1, 6), interval=1, blit=True):
        ani = animation.FuncAnimation(self.fig, self.animate, frames=frames,
                                      interval=interval, blit=blit)
        plt.show()

class Heart02(Heart01):

    def show(self):
        super().show(blit=False)

class Heart03(Heart01):

    def __init__(self):
        super().__init__()
        self.eq = sympy.Eq(
            self.x**2 + (self.y - sympy.sqrt(sympy.Abs(self.x)))**2 - self.a, 0)

class Heart04(Heart03):

    def show(self):
        super().show(blit=False)

class Heart05(Heart01):

    def __init__(self):
        super().__init__()
        self.eq = sympy.Eq(self.x**2 + self.a*(sympy.Rational(3, 5)
                           * (self.x**2)**sympy.Rational(1, 3) - self.y)**2 - 1, 0)

class Heart06(Heart05):

    def show(self):
        super().show(blit=False)

class Heart07(Heart01):

    def __init__(self):
        super().__init__()
        self.eq = sympy.Eq(self.x**2 + 2*(sympy.Rational(3, 5) *
                           (self.x**2)**sympy.Rational(1, 3) - self.y)**2 - self.a, 0)

class Heart08(Heart07):

    def show(self):
        super().show(blit=False)

class Heart3d01:

    def __init__(self):
        self.fig, self.ax = self.plot_setup()

    def plot_setup(self):
        fig = plt.figure(figsize=(8, 8))
        fig.tight_layout(pad=0)
        ax = fig.add_subplot(111, projection='3d')
        return fig, ax

    def plot_implicit(self, fn, bbox=(-2.5, 2.5), resolution=100, slices=30,
                      colormap=plt.cm.Reds):
        """Create a plot of an implicit function fn
        Adapted from https://stackoverflow.com/a/4687582/8706250

        Parameters
        ----------
        fn : function
            implicit funcion with fn == 0
        bbox : tuple, optional
            x, y, z limits, by default (-2.5, 2.5)
        resolution : int, optional
            number of points, by default 100
        slices : int, optional
            number of countour planes, by default 30
        colormap : _type_, optional
            Matplotlib colormap to be used, by default plt.cm.Reds
        """

        xmin, xmax, ymin, ymax, zmin, zmax = bbox * 3
        A = np.linspace(xmin, xmax, resolution)
        B = np.linspace(xmin, xmax, slices)
        A1, A2 = np.meshgrid(A, A)
        colors = [colormap(i) for i in np.linspace(0.0, 1.0, slices)]

        for z, color in zip(B, colors):  # plot contours in the XY plane
            X, Y = A1, A2
            Z = fn(X, Y, z)
            self.ax.contour(X, Y, Z+z, [z], zdir='z',
                            colors=np.array(color).reshape(-1, 4))

        for y, color in zip(B, colors):  # plot contours in the XZ plane
            X, Z = A1, A2
            Y = fn(X, y, Z)
            self.ax.contour(X, Y+y, Z, [y], zdir='y',
                            colors=np.array(color).reshape(-1, 4))

        for x, color in zip(B, colors):  # plot contours in the YZ plane
            Y, Z = A1, A2
            X = fn(x, Y, Z)
            self.ax.contour(X+x, Y, Z, [x], zdir='x',
                            colors=np.array(color).reshape(-1, 4))

        self.ax.set_zlim3d(zmin, zmax)
        self.ax.set_xlim3d(xmin, xmax)
        self.ax.set_ylim3d(ymin, ymax)
        self.ax.grid(False)
        self.ax.set_axis_off()

    @staticmethod
    def heart3D(x, y, z, n=0):
        return (x**2 + (9/4) * y**2 + z**2 - 1)**3 - x**2 * z**3 - (9/80) * y**2 * z**3 < n

    def animate(self, i):
        self.ax.view_init(elev=30, azim=3.6*i)
        return self.fig,

    def show(self):
        self.plot_implicit(self.heart3D, bbox=(-1.3, 1.3),
                           colormap=plt.cm.PuRd, slices=50)
        ani = animation.FuncAnimation(self.fig, self.animate,
                                      frames=100, interval=10, blit=False)

        plt.tight_layout()
        plt.show()

class Heart3d02(Heart3d01):

    def __init__(self):
        super().__init__()
        self.ax.view_init(elev=30, azim=90)

    def animate(self, i):
        self.ax.dist = i
        return self.fig,

    def show(self):
        self.plot_implicit(self.heart3D, bbox=(-1.3, 1.3),
                           colormap=plt.cm.PuRd, slices=50)
        ani = animation.FuncAnimation(self.fig, self.animate, frames=(10, 20),
                                      interval=300, blit=False)

        plt.tight_layout()
        plt.show()

def cli():

    while True:
        try:
            print('\n\nWelcome to matplotlove!! By chicolucio', end='\n\n')
            print('Press 2 for 2D or 3 for 3D')
            choice_2d_3d = input('Do you want a 2D or a 3D heart? ')
        except KeyboardInterrupt:
            print('\nNo more love :-(')
            break
        else:
            if choice_2d_3d == '2':
                options_2d = input('Choose a number between 1 and 4: ')
                if int(options_2d) in range(1, 5):
                    eval(f'Heart0{options_2d}().show()')
                    break
                else:
                    print('Invalid number', end='\n\n')
            elif choice_2d_3d == '3':
                options_3d = input('Choose a number between 1 and 2: ')
                if int(options_3d) in range(1, 3):
                    eval(f'Heart3d0{options_3d}().show()')
                    break
                else:
                    print('Invalid number', end='\n\n')
            else:
                print('Invalid answer', end='\n\n')

if __name__ == "__main__":
    cli()


import numpy as np

def checkDiagonal(arr):
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            if i == j:
                continue
            else:
                if abs(arr[i][j]) > 0.001:
                    return False
    return True

def qrFactorization(arr):
    temp = arr
    i = 0
    while (True):
        Q, R = np.linalg.qr(temp)
        temp = np.dot(R, Q)
        if (checkDiagonal(temp)):
            print("Number of Factorizations: " + str(i + 1))
            break
        else:
            i += 1
    return temp

def printLambda(arr):
    count = 1
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            if (i == j):
                temp = arr[i][j]
                if (abs(temp) < 0.000000000001):
                    temp = 0
                print("Lamda" + str(count) + ": " + str(temp))
                count += 1

def read():
    f = open('matrix.txt', 'r')
    temp = f.read().split('\n')
    arr = []
    for i in temp:
        if i == '':
            continue
        arr.append(i.split(" "))
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            arr[i][j] = int(arr[i][j])
    return arr

def main():
    arr = read()
    eigenvalues = np.linalg.eigvals(arr)
    matrix = np.array(arr)
    print(matrix)
    printLambda(qrFactorization(arr))

if __name__ == '__main__':
    main()


import numpy as np

def prox_l1(x, gamma):
    """
    The proximal operator for the l1_norm

    Parameters:
    -----------
    x : vector or matrix to calculate the norm from
    """
    sgn = np.sign(x)
    S = np.abs(x) - gamma
    S[S < 0.0] = 0.0
    return sgn * S

def prox_l1_01(x, gamma):
    """
    The proximal operator for the l1_norm with value constraint x in [0,1]

    Parameters:
    -----------
    x : vector or matrix to calculate the norm from
    """
    sgn = np.sign(x)
    S = np.abs(x) - gamma
    S[S < 0.0] = 0.0
    S = sgn * S
    S[S < 0.0] = 0
    S[S > 1.0] = 1
    return S

class ProximalGradSolver():
    def __init__(self, gamma, alpha, g, h, dg, prox_h):
        """
	Solves a problem of the form: min alpha*g(x) + h(x),
	where g(x) is smooth and differentiable and h(x) is non-differentiable (e.g. a regularization term or
        indicator function for a value constraint. Alpha is a trade-off variable and lambda is the step-size for
	the proximal gradient step.

	Parameters:
	-----------
	  lambda : step size for proximal gradient step
	  alpha : trade-off variable (problem dependent)
	  g : the differentiable function
          dg : the first derivative of g
	  prox_h : the proximal operator for h
	"""
        self.gamma = gamma
        self.alpha = alpha
        self.g = g
        self.h = h
        self.dg = dg
        self.prox_h = prox_h

    def proximal_step(self, x, gamma):
        """
        Proximal gradient update step

        Parameters:
        -----------
	  x : the current argument
	  gamma : the step size
        """
        x_new = self.prox_h(x - gamma * self.alpha * self.dg(x), gamma)
        return x_new

    def minimize(self, x0, n_iter=50):
        """
       Proximal gradient minimization

       Parameters:
       -----------
	 x0 : the initial argument
	 n_iter : number of steps
       """
        result = x0
        for n in np.arange(n_iter):
            result = self.proximal_step(result, self.gamma)
            costG = self.g(result)
            costH = self.h(result)
            print("Iteration :" + str(n) + " with g(x): " + str(costG) + " and h(x): " + str(costH))
        return result


import numpy as np

def planeRotation1(size,theta,j,k):
    """Compute the rotation matrix
       in the plane of columns j an k (j < k)
       by angle theta (in radians)."""

    protation = np.identity(size)
    protation[j,j] = np.cos(theta)
    protation[k,j] = np.sin(theta)
    protation[k,k] = np.cos(theta)
    protation[j,k] = -1*np.sin(theta)

    return protation

def planeRotation2(size,cos_theta,sin_theta,j,k):
    """Compute the rotation matrix
       in the plane of columns j an k (j < k)
       by cos_theta and sin_theta."""

    protation = np.identity(size)
    protation[j,j] = cos_theta
    protation[k,j] = sin_theta
    protation[k,k] = cos_theta
    protation[j,k] = -1*sin_theta

    return protation


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

import math
import numpy as np

def gen_gaussian_list(a, b, n=1000):

    dx = (b-a)/(n-1)                         # spacing between points
    x = [a + k*dx for k in range(n)]         # domain list

    # Local implementation of a Gaussian function
    def gauss(x):
        return (1/math.sqrt(2*math.pi))*math.exp(-x**2/2)

    g = [gauss(xk) for xk in x]                  # range list
    return (x, g)

def gen_gaussian_array(a, b, n=1000):

    x = np.linspace(a, b, endpoint=True, num=n)

    def gauss(x):
        return (1/np.sqrt(2*np.pi))*np.exp(-x**2/2)

    g = gauss(x)
    return (x, g)

def sinc_list(a, b, n=1000):

    dx = (b-a)/(n-1)                         # spacing between points
    x = [a + k*dx for k in range(n)]         # domain list
    x.remove(0)

    def sinc(x):
        return ((math.sin(x)/x))
    s = [sinc(xk) for xk in x]
    return (x,s)

def sinc_array(a, b, n=1000):

    x = np.linspace(a, b, endpoint=True, num=n)

    def sinc(x):
        ones = np.ones_like(x)
        return(np.divide(np.sin(x), x, out = ones, where=x!=0))

    s = sinc(x)
    return (x, s)

def sinf_list(a, b, n=1000):

    x = np.linspace(a, b, endpoint=True, num=n)

    def sinf(x):
        ones = np.ones_like(x)
        return(np.sin(np.divide(1, x, out = ones, where=x!=0)))

    s = sinf(x)
    return (x, s)

def main(a,b,n=1000):

    x, g = gen_gaussian_list(a,b,n)
    for (xk, gk) in zip(x, g):
        print("({}, {})".format(xk, gk))

# Protected main block for command line operation
if __name__ == "__main__":
    import sys

    if len(sys.argv) == 4:
        a = float(sys.argv[1])
        b = float(sys.argv[2])
        n = int(sys.argv[3])
        main(a,b,n)
    elif len(sys.argv) == 3:
        a = float(sys.argv[1])
        b = float(sys.argv[2])
        main(a,b)
    else:
        print("Usage: cw07.py a b [n]")
        print("  a : float, lower bound of domain")
        print("  b : float, upper bound of domain")
        print("  n : integer, number of points in domain")
        exit(1)


# This little solver is only good for *bounded* LPs of the form
# maximize cx
# subject to: Ax <= b

from sympy import *
from itertools import combinations

def enumeratevertices(A, b):
    '''enumerates all the vertices of {x | Ax <= b}'''
    m, n = A.rows, A.cols

    for rowlist in combinations(range(m), n):
        Ap = A.extract(rowlist, range(n))
        bp = b.extract(rowlist, [0])

        if Ap.det() != 0:
            xp = Ap.LUsolve(bp)

            d = A * xp - b
            feasible = True
            for i in range(m):
                if d[i] > 0:
                    feasible = False

            if feasible:
                yield xp

def findoptimum(A, b, c):
    '''finds the optimum using vertex enumeration'''
    m, n = A.rows, A.cols

    bestvalue, bestvertex = None, None
    for vertex in enumeratevertices(A, b):
        if not bestvalue or (vertex.T * c)[0] > bestvalue:
            bestvalue = (vertex.T * c)[0]
            bestvertex = vertex

    return bestvertex

def solve(A, b, c):
    x = findoptimum(A, b, c)

    if not x:
        print 'LP is infeasible'
    else:
        print 'Vertex', x.T, 'is optimal'
        print 'Optimal value is', (c.T * x)[0]

if __name__ == '__main__':

    # example
    A = Matrix([[50, 24],
         [30, 33],
         [-1, 0],
         [0, -1]])
    b = Matrix([2400, 2100, -45, -5])
    c = Matrix([1, 1])

    solve(A, b, c)


## This is based the work of Christopher Flynn fbm in
# https://github.com/crflynn/fbm and Davies, Robert B., and D. S. Harte. “Tests
# for Hurst effect.” Biometrika 74, no. 1 (1987): 95-101.

import numpy as np

def fgn(N: int, H: float) -> np.ndarray:
    """
    Generates fractional Gaussian noise with a Hurst index H in (0,1). If
    H = 1/2 this is simply Gaussian noise.
    The current method employed is the Davies–Harte method, which fails for
    H ≈ 0. A Cholesky decomposition method and the Hosking’s method will be
    implemented in later versions.

    Parameters
    ----------
    N: int
        Size of fractional Gaussian noise to generate.

    H: float
        Hurst exponent H in (0,1).

    Returns
    -------
    f: np.ndarray
        A array of size N of fractional Gaussian noise with a Hurst index H.
    """

    # Asserts
    assert isinstance(N, int), "Size must be an integer number"
    assert isinstance(H, float), "Hurst index must be a float in (0,1)"

    # Generate linspace
    k = np.linspace(0,N-1,N)

    # Correlation function
    cor = 0.5*(abs(k - 1)**(2*H) - 2*abs(k)**(2*H) + abs(k + 1)**(2*H))

    # Eigenvalues of the correlation function
    eigenvals = np.sqrt(
                  np.fft.fft(
                    np.concatenate([cor[:],0,cor[1:][::-1]],axis = None).real
                  )
                )

    # Two normal distributed noises to be convoluted
    gn = np.random.normal(0.0, 1.0, N)
    gn2 = np.random.normal(0.0, 1.0, N)

    # This is the Davies–Harte method
    w = np.concatenate(
        [(eigenvals[0]   / np.sqrt(2*N)) * gn[0],
         (eigenvals[1:N] / np.sqrt(4*N)) *(gn[1:] + 1j*gn2[1:]),
         (eigenvals[N]   / np.sqrt(2*N)) * gn2[0],
         (eigenvals[N+1:]/ np.sqrt(4*N)) *(gn[1:][::-1] - 1j*gn2[1:][::-1])
        ],
        axis = None)

    # Perform fft. Only first N entry are useful
    f = np.fft.fft(w).real[:N] * ( (1.0 / N) ** H )

    # TODO: Check for further speed-ups
    # TODO: Generalise for several outputs. Should be straightforward.
    # TODO: Implement the Cholesky decomposition method
    # TODO: Implement the Hosking’s method
    return f


import math
import random
from dataclasses import dataclass
from typing import ClassVar, Generator

from common import almost_equal

from scipy.spatial import distance

@dataclass
class Point:
    x: float
    y: float

def euclidean_distance(a: Point, b: Point) -> float:
    return distance.euclidean((a.x, a.y), (b.x, b.y))

class UnitCircle:
    center: ClassVar[Point] = Point(0.5, 0.5)
    radius: ClassVar[float] = 0.5

    def contains(self, point: Point) -> bool:
        return euclidean_distance(point, self.center) < self.radius

def simulate(n_iter: int) -> float:
    unit_circle = UnitCircle()
    random_points: Generator[Point] = (Point(x=random.random(), y=random.random()) for _ in range(n_iter))
    num_points_within_circle: int = sum(
        [1 if unit_circle.contains(point) else 0 for point in random_points]
    )

    return (float(num_points_within_circle) / n_iter) * 4

assert almost_equal(simulate(100000), math.pi)


import numpy as np
import math as mth

#kernel density estimation method with a Gaussian kernel with standard deviation h (Seite 123 Bishop buch)
def kde(samples, h):
    # compute density estimation from samples with KDE
    # Input
    #  samples    : DxN matrix of data points
    #  h          : (half) window size/radius of kernel
    # Output
    #  estDensity : estimated density in the range of [-5,5]
    pos = np.arange(-5, 5.0, 0.1)  # Returns a 100 dimensional vector

    n = samples.shape[0]
    #d = pos.shape[0]
    d = 1

    temp_value = []
    for x in pos:
        summe = 0
        for j in range(0, n-1): # summe von 1 bis n
            diff_norm = np.linalg.norm(x - samples[j])
            summe += 1/(pow(2*mth.pi*pow(h,2),d/2))*mth.exp(-1*pow(diff_norm,2)/(2*pow(h,2)))
        p_x = 1/n * summe
        temp_value.append(p_x)

    value = np.array(temp_value)
    estDensity = np.column_stack((pos, value))

    return estDensity


import numpy as np

def multiDimensionalNormal(mean, covariance, value):
    D = len(value)

    normalizationFactor = 1/((2*np.pi)**(D/2)*np.linalg.det(covariance)**(0.5))

    distribution = np.exp(-0.5 * (np.transpose(value-mean) @ np.linalg.inv(covariance) @ (value-mean)))

    return normalizationFactor*distribution

def getLogEntry(means, weights, covariances, value):
    K = means.shape[0]

    innerSum = 0
    for k in range(K):
        innerSum += weights[k]*multiDimensionalNormal(means[k], covariances[:,:,k], value)

    return np.log(innerSum)

def getLogLikelihood(means, weights, covariances, X):
    # Log Likelihood estimation
    #
    # INPUT:
    # means          : Mean for each Gaussian KxD
    # weights        : Weight vector 1xK for K Gaussians
    # covariances    : Covariance matrices for each gaussian DxDxK
    # X              : Input data NxD
    # where N is number of data points
    # D is the dimension of the data points
    # K is number of gaussians
    #
    # OUTPUT:
    # logLikelihood  : log-likelihood

    means = np.array(means)
    weights = np.array(weights)

    sumOverDataPoints = 0
    for n in range(X.shape[0]):
        sumOverDataPoints += getLogEntry(means, weights, covariances, X[n])

    return sumOverDataPoints


import math
import numpy as np
import time

import matplotlib.pyplot as plt

#------------------------
#system configuration

num_of_classes = 2 #1 for regression, n for classification
epoch = 1000
learningRate = np.array([0.1])
hidden_layers = [5, 5]

print("system configuration: epoch=",epoch,", hidden layers=",hidden_layers)

optimization_algorithm = 'adam' #gradient-descent or adam

#------------------------
#trainset

x = np.array( #xor dataset
	[ #bias, #x1, #x2
		[[1],[0],[0]], #instance 1
		[[1],[0],[1]], #instance 2
		[[1],[1],[0]], #instance 3
		[[1],[1],[1]]  #instace 4
	]
)

if num_of_classes > 1: #classification
	y = np.array(
		[
			[[1],[0]],
			[[0],[1]],
			[[0],[1]],
			[[1],[0]],
		]
	)
else: #regression
	y = np.array(
		[
			[0], #instance 1
			[1], #instance 2
			[1], #instance 3
			[0]  #instace 4
		]
	)

"""
#suppose that traindata stored in this file. each line refers to an instance.
#final item of an instance is label (y) whereas the other ones are features  (x)
#now, loading trainset from external resource is available for regression problems
from numpy import genfromtxt
dataset = genfromtxt('../xor.csv', delimiter=',')
features = dataset[:,0:dataset.shape[1]-1]
labels = dataset[:,dataset.shape[1]-1:]
bias = np.array([1]);
x = [0 for i in range(features.shape[0])]
for i in range(features.shape[0]):
	x[i] = np.array([np.append([1], features[i])]).T
y = [0 for i in range(labels.shape[0])]
for i in range(labels.shape[0]):
	if num_of_classes == 1: #regression
		y[i] = np.array([labels[i]]).T
	else:
		encoded = [0 for i in range(num_of_classes)]
		encoded[int(labels[i])] = 1
		y[i] = np.array([encoded]).T
x = np.array(x)
y = np.array(y)
"""
#print("features: ",x)
#print("target: ",y)
#------------------------

num_of_features = x.shape[1]-1 #minus 1 refers to bias
num_of_instances = x.shape[0]
num_of_layers = len(hidden_layers) + 2 #plus input layer and output layer

#------------------------
def initialize_weights(rows, columns):
	#lecture: https://www.coursera.org/learn/deep-neural-network/lecture/RwqYe/weight-initialization-for-deep-networks
	weights = np.random.randn(rows+1, columns) #standard normal distribution, +1 refers to bias unit
	weights = weights * np.sqrt(1/rows) #xavier initialization. this is good for tanh (http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf)
	#weights = weights * np.sqrt(2/rows) #this is good for relu (https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/He_Delving_Deep_into_ICCV_2015_paper.pdf)
	#weights = weights * np.sqrt(6/(rows + columns)) #normalized initialization (same ref with xavier initialization)
	return weights

#weight initialization
w = [0 for i in range(num_of_layers-1)]

w[0] = initialize_weights(num_of_features, hidden_layers[0])

if len(hidden_layers) > 1:
	for i in range(len(hidden_layers) - 1):
		w[i+1] = initialize_weights(hidden_layers[i], hidden_layers[i+1])

w[num_of_layers-2] = initialize_weights(hidden_layers[len(hidden_layers) - 1], num_of_classes)

#print("initial weights: ", w)
#------------------------

def sigmoid(netinput):
	netoutput = np.ones((netinput.shape[0] + 1, 1))
	#ones because init values are same as bias unit
	#size of output is 1 plus input because of bias

	for i in range(netinput.shape[0]):
		netoutput[i+1] = 1/(1 + math.exp(-netinput[i][0]))
	return netoutput

def applyFeedForward(x, w):

	netoutput = [i for i in range(num_of_layers)]
	netinput = [i for i in range(num_of_layers)]

	netoutput[0] = x
	for i in range(num_of_layers - 1):
		netinput[i+1] = np.matmul(np.transpose(w[i]), netoutput[i])
		netoutput[i+1] = sigmoid(netinput[i+1])

	netoutput[num_of_layers-1] = netoutput[num_of_layers-1][1:] #bias should not exist in output
	return netoutput

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

start_time = time.time()

def calculateCost():
	cost = 0
	for i in range(num_of_instances):
		nodes = applyFeedForward(x[i], w)
		predict = nodes[num_of_layers - 1]
		actual = y[i]

		cost = cost + sum(pow((actual - predict), 2)/2)

	cost = cost / num_of_instances
	return cost

#adam optimization parameters initialization
vdw = [0.0 for i in range(num_of_layers)]
sdw = [0.0 for i in range(num_of_layers)]
epsilon = np.array([pow(10, -8)])
beta1 = 0.9; beta2 = 0.999

J = [] #cost history
J.append(calculateCost()) #initial cost

for epoch in range(epoch):
	for i in range(num_of_instances):
		instance = x[i]
		nodes = applyFeedForward(instance, w)

		predict = nodes[num_of_layers - 1]
		actual = y[i]
		#print("predict: ",predict,", actual: ",actual)
		error = actual - predict
		#print("error: ",error)

		sigmas = [i for i in range(num_of_layers)] #error should not be reflected to input layer

		sigmas[num_of_layers - 1] = error
		for j in range(num_of_layers - 2, -1, -1):

			if sigmas[j + 1].shape[0] == 1:
				sigmas[j] = w[j] * sigmas[j + 1]
			else:
				if j == num_of_layers - 2: #output layer has no bias unit
					sigmas[j] = np.matmul(w[j], sigmas[j + 1])
				else: #otherwise remove bias unit from the following node because it is not connected from previous layer
					sigmas[j] = np.matmul(w[j], sigmas[j + 1][1:])

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

		derivative_of_sigmoid = nodes * (np.array([1]) - nodes) #element wise multiplication and scalar multiplication
		sigmas = derivative_of_sigmoid * sigmas

		for j in range(num_of_layers - 1):

			if j == num_of_layers - 2: #outputlayer
				delta = nodes[j] * np.transpose(sigmas[j+1]) #no bias exist in output layer
			else:
				delta = nodes[j] * np.transpose(sigmas[j+1][1:])

			#-----------------------------------------------
			#optimization algorithm
			if optimization_algorithm == 'gradient-descent':
				w[j] = w[j] + learningRate * delta
			elif optimization_algorithm == 'adam':
				vdw[j] = beta1 * vdw[j] + (1 - beta1) * delta
				sdw[j] = beta2 * sdw[j] + (1 - beta2) * pow(delta, 2)

				vdw_corrected = vdw[j] / (1-pow(beta1, epoch+1))
				sdw_corrected = sdw[j] / (1-pow(beta2,epoch+1))

				w[j] = w[j] + learningRate * (vdw_corrected / (np.sqrt(sdw_corrected) + epsilon))
			##optimization algorithm end
	J.append(calculateCost())

#training end

x_axis = [i for i in range(len(J))]
plt.plot(x_axis, J, c='blue', label=optimization_algorithm)
plt.xlabel('epoch')
plt.ylabel('error')
plt.show()

#---------------------
print("--- execution for vectorization lasts %s seconds ---" % (time.time() - start_time))

#print("final weights: ",w)

for i in range(num_of_instances):
	nodes = applyFeedForward(x[i], w)
	predict = nodes[num_of_layers - 1]
	actual = y[i]
	print(np.transpose(x[i][1:])," -> actual: ", np.transpose(actual)[0],", predict: ", np.transpose(predict)[0])


import numpy as np

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

t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
print(mean_squared_error(np.array(y), np.array(t)))

y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(mean_squared_error(np.array(y), np.array(t)))


from collections import namedtuple
import sympy  # prime numbers manipulation
import random  # random integers generation

PUBLIC_KEY = namedtuple('Public_Key', ('enc_exponent', 'modulus'))
PRIVATE_KEY = namedtuple('Private_Key', ('dec_exponent', 'modulus'))

class Repository:
    """
    Public keys repository.
    """

    def __init__(self):
        self.public_keys = {}

    def add_key(self, name, key):
        """
        Adds a public key associated with a name to the repository.
        ---
        Args:
            - name(string): name of the key holder.
            - key(namedtuple): public key following the namedtuple convention above.
        Returns:
            - True if all goes well.
        """
        self.public_keys[name] = key

    def get_key(self, name):
        """
                Returns the public key from the holder's name.
                ---
                Args:
                        - name(String): key holder.
                Returns:
                        - public_key(NamedTuple): public key of the specified holder if it exists.
        """
        try:
            return self.public_keys[name]
        except Exception:
            print('Non-existing key. Check the key holder\'s name.')

    def get_all_keys(self):
        """
        Prints all existing keys.
        """
        for name in self.public_keys.keys():
            print(name + ': ', self.get_key(name))

class RSAInstance:
    """
    The RSA instance holding two keys: a public and a private key.
    It can send and receive messages from another RSA instance.
    """

    def __init__(self, name):
        self.name = name
        self.public_key = None
        self.private_key = None

        self._generate_keys()

    def _generate_keys(self):
        """
        function to generate the public and private key
        for the current instance.
        """
        # generate two prime numbers p and q in the interval [Lower, Upper]
        LOWER_BOUND = 0
        UPPER_BOUND = 10e2

        p = sympy.randprime(LOWER_BOUND, UPPER_BOUND)

        # generate q that is different from p
        q = p
        while q == p:
            q = sympy.randprime(LOWER_BOUND, UPPER_BOUND)

        # check whether p and q are both primes and are different numbers
        assert sympy.isprime(p)
        assert sympy.isprime(q)
        assert p != q

        # computing the modulus
        modulus = p * q

        # computing the totient of the modulus
        totient = (p - 1) * (q - 1)

        # selecting the encryption exponent in the interval ]1, totient[
        enc_exponent = 0
        while sympy.gcd(enc_exponent, totient) != 1:
            enc_exponent = random.randrange(2, totient)

        # create public key
        self.public_key = PUBLIC_KEY(enc_exponent, modulus)

        # decryption exponent
        dec_exponent = sympy.mod_inverse(enc_exponent, totient)

        # create private key
        self.private_key = PRIVATE_KEY(dec_exponent, modulus)

        # self.public_key = public_key(947, 8383)
        # self.private_key = private_key(7083, 8383)

    def encrypt(self, msg, to):
        """
        encrypting a message before sending it to another RSA instance.
        ---
        Args:
            - msg(String): message to be sent - Plaintext.
            - to(RSAInstance): receiver.
        Returns:
                - cipher(String): ciphered plaintext.
        """
        ascii_ = ""
        cipher = ""

        # convert string msg to ascii
        for character in msg:
            ascii_ += str(ord(character)) + " "

        # encrypt using public key of the receiver.
        for character in ascii_.strip().split(' '):
            cipher += str((int(character)**to.public_key.enc_exponent) %
                          to.public_key.modulus) + ' '

        return cipher

    def decrypt(self, cipher, from_, dig_sign=False):
        """
        decrypting a message encrypted by another RSA instance.
        ---
        Args:
            - msg(String): message to be sent - Plaintext.
            - to(RSAInstance): receiver.
        Returns:
            - cipher(String): ciphered plaintext.
        """
        # if dig_sign is true => decrypt using public key of from_
        ascii_ = ""
        res = ""

        # decryption using own private key
        for character in cipher.strip().split(' '):
            ascii_ += str((int(character)**self.private_key.dec_exponent) %
                          self.private_key.modulus) + ' '

        # convert ascii to char
        for character in ascii_.strip().split(' '):
            res += chr(int(character))

        return res


import numpy as np
from random import random, uniform
import matplotlib.pyplot as plt

def ackley(x, a=20, b=0.2, c=2*np.pi):
    # n dimensional
    x = np.asarray_chkfinite(x)  # ValueError if any NaN or Inf
    n = len(x)
    s1 = sum(x**2)
    s2 = sum(np.cos(c * x))
    return -a*np.exp(-b*np.sqrt(s1 / n)) - np.exp(s2 / n) + a + np.exp(1)

def bukin(x):
    # 2 dimensional
    return 100 * np.sqrt(np.abs(x[1] - 0.01 * x[0] ** 2)) + 0.01 * np.abs(x[0] + 10)

def griewank(x):
    # n dimensional
    dim = len(x)
    j = np.arange(1, dim + 1)
    sq_list = [i ** 2 for i in x]
    s = sum(sq_list)
    p = np.prod(np.cos(x / np.sqrt(j)))
    return s / 4000 - p + 1

def rosenbrock(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    x0 = x[:-1]
    x1 = x[1:]
    return sum(100 * (x1 - x0 ** 2) ** 2 + (x0 - 1) ** 2)

def zakharov(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    dim = len(x)
    j = np.arange(1, dim + 1)
    s1 = sum(0.5 * j * x)
    return sum(x ** 2) + s1 ** 2 + s1 ** 4

def levy(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    w = 1 + (x - 1) / 4
    return (np.sin(np.pi * w[0])) ** 2 \
        + sum((w[:-1] - 1) ** 2 * (1 + 10 * np.sin(np.pi * w[:-1] + 1) ** 2)) \
        + (w[-1] - 1) ** 2 * (1 + (np.sin(2 * np.pi * w[-1]) ** 2))

def rastrigin(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    dim = len(x)
    return 10 * dim + sum(x ** 2 - 10 * np.cos(2 * np.pi * x))

def schwefel(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    dim = len(x)
    return 418.9829 * dim - sum(x * np.sin(np.sqrt(np.abs(x))))

def sphere(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    return sum(x ** 2)

def sum_diff_powers(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    dim = len(x)
    j = np.arange(1, dim + 1)
    return sum(np.abs(x) ** (j + 1))

def sum_of_squares(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    dim = len(x)
    j = np.arange(1, dim + 1)
    return sum(j * x ** 2)

def rotated_hyper_ellipsoid(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    dim = len(x)
    total = 0
    for i in range(1, dim + 1):
        for j in range(1, i + 1):
            total += (x[j - 1] ** 2)
    return total

def ellipse(x):
    # n dimensional
    x = np.asarray_chkfinite(x)
    return np.mean((1 - x) ** 2) + 100 * np.mean(np.diff(x) ** 2)

def schafferN6(x):
    # 2 dimensional
    x = np.asarray_chkfinite(x)
    num = np.sin(np.sqrt(x[0] ** 2 + x[1] ** 2)) ** 2 - 0.5
    denom = (1 + 0.001*(x[0] ** 2 + x[1] ** 2)) ** 2
    return 0.5 + num / denom

def simple_parabola(x):
    x = np.asarray(x)
    return -3 * x ** 2 + 3

def beamline_test_function(x):
    x = np.asarray(x)
    return np.sin(4 * x) - np.cos(8 * x) + 2

def ensure_bounds(vec, bounds):
    # Makes sure each individual stays within bounds and adjusts them if they aren't
    vec_new = []
    # cycle through each variable in vector
    for i in range(len(vec)):
        # variable exceeds the minimum boundary
        if vec[i] < bounds[i][0]:
            vec_new.append(bounds[i][0])
        # variable exceeds the maximum boundary
        if vec[i] > bounds[i][1]:
            vec_new.append(bounds[i][1])
        # the variable is fine
        if bounds[i][0] <= vec[i] <= bounds[i][1]:
            vec_new.append(vec[i])
    return vec_new

def omea(positions, func):
    evaluations = []
    min_positions = []
    min_evals = []
    # get first position eval
    evaluations.append(func(positions[0]))

    for i in range(1, len(positions)):
        hold_eval = []
        in_between = np.linspace(positions[i - 1], positions[i], 50)
        between = in_between[1:-1]
        for t in range(len(between)):
            hold_eval.append(func(between[t]))
        # get eval of next position
        evaluations.append(func(positions[i]))
        # find index of min
        ii = np.argmin(hold_eval)
        min_positions.append(between[ii])
        min_evals.append(hold_eval[ii])
    for i in range(len(min_positions)):
        if min_evals[i] < evaluations[i + 1]:
            evaluations[i + 1] = min_evals[i]
            for k in range(len(min_positions[i])):
                positions[i + 1][k] = min_positions[i][k]
    return positions, evaluations

def rand_1(pop, popsize, t_indx, mut, bounds):
    # v = x_r1 + F * (x_r2 - x_r3)
    idxs = [idx for idx in range(popsize) if idx != t_indx]
    a, b, c = np.random.choice(idxs, 3, replace=False)
    x_1 = pop[a]
    x_2 = pop[b]
    x_3 = pop[c]

    x_diff = [x_2_i - x_3_i for x_2_i, x_3_i in zip(x_2, x_3)]
    v_donor = [x_1_i + mut * x_diff_i for x_1_i, x_diff_i in zip(x_1, x_diff)]
    v_donor = ensure_bounds(v_donor, bounds)
    return v_donor

def best_1(pop, popsize, t_indx, mut, bounds, ind_sol):
    # v = x_best + F * (x_r1 - x_r2)
    x_best = pop[ind_sol.index(np.min(ind_sol))]
    idxs = [idx for idx in range(popsize) if idx != t_indx]
    a, b = np.random.choice(idxs, 2, replace=False)
    x_1 = pop[a]
    x_2 = pop[b]

    x_diff = [x_1_i - x_2_i for x_1_i, x_2_i in zip(x_1, x_2)]
    v_donor = [x_b + mut * x_diff_i for x_b, x_diff_i in zip(x_best, x_diff)]
    v_donor = ensure_bounds(v_donor, bounds)
    return v_donor

def current_to_best_1(pop, popsize, t_indx, mut, bounds, ind_sol):
    # v = x_curr + F * (x_best - x_curr) + F * (x_r1 - r_r2)
    x_best = pop[ind_sol.index(np.min(ind_sol))]
    idxs = [idx for idx in range(popsize) if idx != t_indx]
    a, b = np.random.choice(idxs, 2, replace=False)
    x_1 = pop[a]
    x_2 = pop[b]
    x_curr = pop[t_indx]

    x_diff1 = [x_b - x_c for x_b, x_c in zip(x_best, x_curr)]
    x_diff2 = [x_1_i - x_2_i for x_1_i, x_2_i in zip(x_1, x_2)]
    v_donor = [x_c + mut * x_diff_1 + mut * x_diff_2 for x_c, x_diff_1, x_diff_2
               in zip(x_curr, x_diff1, x_diff2)]
    v_donor = ensure_bounds(v_donor, bounds)
    return v_donor

def best_2(pop, popsize, t_indx, mut, bounds, ind_sol):
    # v = x_best + F * (x_r1 - x_r2) + F * (x_r3 - r_r4)
    x_best = pop[ind_sol.index(np.min(ind_sol))]
    idxs = [idx for idx in range(popsize) if idx != t_indx]
    a, b, c, d = np.random.choice(idxs, 4, replace=False)
    x_1 = pop[a]
    x_2 = pop[b]
    x_3 = pop[c]
    x_4 = pop[d]

    x_diff1 = [x_1_i - x_2_i for x_1_i, x_2_i in zip(x_1, x_2)]
    x_diff2 = [x_3_i - x_4_i for x_3_i, x_4_i in zip(x_3, x_4)]
    v_donor = [x_b + mut * x_diff_1 + mut * x_diff_2 for x_b, x_diff_1, x_diff_2
               in zip(x_best, x_diff1, x_diff2)]
    v_donor = ensure_bounds(v_donor, bounds)
    return v_donor

def rand_2(pop, popsize, t_indx, mut, bounds):
    # v = x_r1 + F * (x_r2 - x_r3) + F * (x_r4 - r_r5)
    idxs = [idx for idx in range(popsize) if idx != t_indx]
    a, b, c, d, e = np.random.choice(idxs, 5, replace=False)
    x_1 = pop[a]
    x_2 = pop[b]
    x_3 = pop[c]
    x_4 = pop[d]
    x_5 = pop[e]

    x_diff1 = [x_2_i - x_3_i for x_2_i, x_3_i in zip(x_2, x_3)]
    x_diff2 = [x_4_i - x_5_i for x_4_i, x_5_i in zip(x_4, x_5)]
    v_donor = [x_1_i + mut * x_diff_1 + mut * x_diff_2 for x_1_i, x_diff_1, x_diff_2
               in zip(x_1, x_diff1, x_diff2)]
    v_donor = ensure_bounds(v_donor, bounds)
    return v_donor

def mutate(population, strategy, mut, bounds, ind_sol):
    mutated_indv = []
    for i in range(len(population)):
        if strategy == 'rand/1':
            v_donor = rand_1(population, len(population), i, mut, bounds)
        elif strategy == 'best/1':
            v_donor = best_1(population, len(population), i, mut, bounds, ind_sol)
        elif strategy == 'current-to-best/1':
            v_donor = current_to_best_1(population, len(population), i, mut, bounds, ind_sol)
        elif strategy == 'best/2':
            v_donor = best_2(population, len(population), i, mut, bounds, ind_sol)
        elif strategy == 'rand/2':
            v_donor = rand_2(population, len(population), i, mut, bounds)
        mutated_indv.append(v_donor)
    return mutated_indv

def crossover(population, mutated_indv, crosspb):
    crossover_indv = []
    for i in range(len(population)):
        v_trial = []
        x_t = population[i]
        for j in range(len(x_t)):
            crossover_val = random()
            if crossover_val <= crosspb:
                v_trial.append(mutated_indv[i][j])
            else:
                v_trial.append(x_t[j])
        crossover_indv.append(v_trial)
    return crossover_indv

def select(population, crossover_indv, ind_sol, func):
    positions = [elm for elm in crossover_indv]
    positions.insert(0, population[0])
    positions, evals = omea(positions, func)
    positions = positions[1:]
    evals = evals[1:]
    for i in range(len(evals)):
        if evals[i] < ind_sol[i]:
            population[i] = positions[i]
            ind_sol[i] = evals[i]
    population.reverse()
    ind_sol.reverse()
    return population, ind_sol

def diff_ev(bounds, func, threshold, popsize=10, crosspb=0.8, mut=0.05, mut_type='rand/1'):
    # Initial population
    population = []
    best_fitness = [10]
    for i in range(popsize):
        indv = []
        for j in range(len(bounds)):
            indv.append(uniform(bounds[j][0], bounds[j][1]))
        population.append(indv)
    init_pop = population[:]

    # Evaluate fitness/OMEA
    init_pop.sort()
    pop, ind_sol = omea(init_pop, func)
    # reverse for efficiency with motors
    pop.reverse()
    ind_sol.reverse()

    # Termination conditions
    v = 0  # generation number
    consec_best_ctr = 0  # counting successive generations with no change to best value
    old_best_fit_val = 0
    while not (consec_best_ctr >= 5 and old_best_fit_val <= threshold):
        print('\nGENERATION ' + str(v + 1))
        best_gen_sol = []  # holding best scores of each generation
        mutated_trial_pop = mutate(pop, mut_type, mut, bounds, ind_sol)
        cross_trial_pop = crossover(pop, mutated_trial_pop, crosspb)
        pop, ind_sol = select(pop, cross_trial_pop, ind_sol, func)

        # score keeping
        gen_best = np.min(ind_sol)  # fitness of best individual
        best_indv = pop[ind_sol.index(gen_best)]  # best individual positions
        best_gen_sol.append(best_indv)
        best_fitness.append(gen_best)

        print('      > BEST FITNESS:', gen_best)
        print('         > BEST POSITIONS:', best_indv)

        v += 1
        if np.round(gen_best, 6) == np.round(old_best_fit_val, 6):
            consec_best_ctr += 1
            print('Counter:', consec_best_ctr)
        else:
            consec_best_ctr = 0
        old_best_fit_val = gen_best

        if consec_best_ctr >= 5 and old_best_fit_val <= threshold:
            print('Finished')
            break
        else:
            change_index = ind_sol.index(np.max(ind_sol))
            changed_indv = pop[change_index]
            for k in range(len(changed_indv)):
                changed_indv[k] = uniform(bounds[k][0], bounds[k][1])
            # OMEA would be here too
            # not sure how to do this with functions
            ind_sol[change_index] = func(changed_indv)

    x_best = best_gen_sol[-1]
    print('\nThe best individual is', x_best, 'with a fitness of', gen_best)
    print('It took', v, 'generations')

    # plot best fitness
    plot_index = np.arange(len(best_fitness))
    plt.figure()
    plt.plot(plot_index, best_fitness)

diff_ev(bounds=[(-10, 10)] * 20, func=sphere, threshold=0.05, popsize=10, crosspb=0.8, mut=0.2)


import torch
import torch.nn as nn
import numpy as np

#
#        -> 2.0              -> 0.65
# Linear -> 1.0  -> Softmax  -> 0.25   -> CrossEntropy(y, y_hat)
#        -> 0.1              -> 0.1
#
#     scores(logits)      probabilities
#                           sum = 1.0
#

# Softmax applies the exponential function to each element, and normalizes
# by dividing by the sum of all these exponentials
# -> squashes the output to be between 0 and 1 = probability
# sum of all probabilities is 1
def softmax(x):
    return np.exp(x) / np.sum(np.exp(x), axis=0)

x = np.array([2.0, 1.0, 0.1])
outputs = softmax(x)
print('softmax numpy:', outputs)

x = torch.tensor([2.0, 1.0, 0.1])
outputs = torch.softmax(x, dim=0) # along values along first axis
print('softmax torch:', outputs)

# Cross entropy
# Cross-entropy loss, or log loss, measures the performance of a classification model
# whose output is a probability value between 0 and 1.
# -> loss increases as the predicted probability diverges from the actual label
def cross_entropy(actual, predicted):
    EPS = 1e-15
    predicted = np.clip(predicted, EPS, 1 - EPS)
    loss = -np.sum(actual * np.log(predicted))
    return loss # / float(predicted.shape[0])

# y must be one hot encoded
# if class 0: [1 0 0]
# if class 1: [0 1 0]
# if class 2: [0 0 1]
Y = np.array([1, 0, 0])
Y_pred_good = np.array([0.7, 0.2, 0.1])
Y_pred_bad = np.array([0.1, 0.3, 0.6])
l1 = cross_entropy(Y, Y_pred_good)
l2 = cross_entropy(Y, Y_pred_bad)
print(f'Loss1 numpy: {l1:.4f}')
print(f'Loss2 numpy: {l2:.4f}')

# CrossEntropyLoss in PyTorch (applies Softmax)
# nn.LogSoftmax + nn.NLLLoss  #注意已经是两个功能集合了
# NLLLoss = negative log likelihood loss
loss = nn.CrossEntropyLoss()
# loss(input, target)

# target is of size nSamples = 1
# each element has class label: 0, 1, or 2
# Y (=target) contains class labels, not one-hot
Y = torch.tensor([0])

# input is of size nSamples x nClasses = 1 x 3
# y_pred (=input) must be raw, unnormalizes scores (logits) for each class, not softmax
Y_pred_good = torch.tensor([[2.0, 1.0, 0.1]])
Y_pred_bad = torch.tensor([[0.5, 2.0, 0.3]])
l1 = loss(Y_pred_good, Y)
l2 = loss(Y_pred_bad, Y)

print(f'PyTorch Loss1: {l1.item():.4f}')
print(f'PyTorch Loss2: {l2.item():.4f}')

# get predictions
_, predictions1 = torch.max(Y_pred_good, 1)
_, predictions2 = torch.max(Y_pred_bad, 1)
print(f'Actual class: {Y.item()}, Y_pred1: {predictions1.item()}, Y_pred2: {predictions2.item()}')

# allows batch loss for multiple samples

# target is of size nBatch = 3
# each element has class label: 0, 1, or 2
Y = torch.tensor([2, 0, 1])  # 注意这里是3个sample

# input is of size nBatch x nClasses = 3 x 3
# Y_pred are logits (not softmax)
Y_pred_good = torch.tensor(
    [[0.1, 0.2, 3.9], # predict class 2
    [1.2, 0.1, 0.3], # predict class 0
    [0.3, 2.2, 0.2]]) # predict class 1

Y_pred_bad = torch.tensor(
    [[0.9, 0.2, 0.1],
    [0.1, 0.3, 1.5],
    [1.2, 0.2, 0.5]])

l1 = loss(Y_pred_good, Y)
l2 = loss(Y_pred_bad, Y)
print(f'Batch Loss1:  {l1.item():.4f}')
print(f'Batch Loss2: {l2.item():.4f}')

# get predictions
_, predictions1 = torch.max(Y_pred_good, 1)
_, predictions2 = torch.max(Y_pred_bad, 1)
print(f'Actual class: {Y}, Y_pred1: {predictions1}, Y_pred2: {predictions2}')

# Binary classification
class NeuralNet1(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(NeuralNet1, self).__init__()
        self.linear1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(hidden_size, 1)

    def forward(self, x):
        out = self.linear1(x)
        out = self.relu(out)
        out = self.linear2(out)
        # sigmoid at the end
        y_pred = torch.sigmoid(out)
        return y_pred

model = NeuralNet1(input_size=28*28, hidden_size=5)
criterion = nn.BCELoss()  #注意loss function的不同

# Multiclass problem
class NeuralNet2(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet2, self).__init__()
        self.linear1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        out = self.linear1(x)
        out = self.relu(out)
        out = self.linear2(out)
        # no softmax at the end
        return out

model = NeuralNet2(input_size=28*28, hidden_size=5, num_classes=3)
criterion = nn.CrossEntropyLoss()  # (applies Softmax)


#ZADANIE 3
#Oblicz i przedstaw odchylenia standardowe bledow dla wszystkich wariantow z zadania 2.
#Przedstaw wnioski.

import numpy as np

def tbernoulli(n):
    if n<0 and n>20:
        return 0
    else:
        temp=[1, 1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66, 0, -691/2730, 0, 7/6, 0, -3617/510, 0, 43867/798, 0, -174611/330]
        return temp[n]

def silnia(x):
    sil = 1
    while x > 0:
        sil = sil * x
        x = x - 1
    return sil

def tsin(x):
    sum_sin=0
    for i in range(0,6):
        sum_sin=sum_sin+((-1)**i)*(x**(2*i+1))/float(silnia(2*i+1))
    return sum_sin

def tcos(x):
    sum_cos=0
    for i in range(0,6):
        sum_cos=sum_cos+((-1)**i)*(x**(2*i))/float(silnia(2*i))
    return sum_cos

def texp(x):
    sum_exp=0
    for i in range(0,6):
        sum_exp=sum_exp+(x**i)/float(silnia(i))
    return sum_exp

def ttan(x):
    sum_tan=0
    for i in range(0,6):
        sum_tan=sum_tan+tbernoulli(2*i)*((-4)**i)*(1-(4**i))*(x**(2*i-1))/float(silnia(2*i))
    return sum_tan

def blad_bw_std(f1,f2,xp,xk,k):
    bledy=[np.abs(f1(i)-f2(i)) for i in np.arange(xp,xk,k)]
    return np.std(bledy)

print("Sin")
print(blad_bw_std(tsin,np.sin,-3*np.pi,0,0.1))
print(blad_bw_std(tsin,np.sin,0,np.pi/4,0.1))
print(blad_bw_std(tsin,np.sin,-3*np.pi,3*np.pi,0.1))

print("\nCos")
print(blad_bw_std(tcos,np.cos,-3*np.pi,0,0.1))
print(blad_bw_std(tcos,np.cos,0,np.pi/4,0.1))
print(blad_bw_std(tcos,np.cos,-3*np.pi,3*np.pi,0.1))

print("\nExp")
print(blad_bw_std(texp,np.exp,0,20,0.1))
print(blad_bw_std(texp,np.exp,0,1,0.1))

print("\nTan")
print(blad_bw_std(ttan,np.tan,-np.pi,2,0.1))
print(blad_bw_std(ttan,np.tan,0.1,np.pi/2,0.1))
print(blad_bw_std(ttan,np.tan,-np.pi/2,np.pi/2,0.1))

#Jezeli zakres danych jest niewielki to algorytm dziala poprawnie.
#Im wiekszy zakres danych tym wieksze bledy.
#Przy szerokim zakresie danych bledy sa bardzo duze.


"""
Calculates surface rougness based on slope standard deviation

Many rougness metrics are based on elevation differences. This could lead to a
flat, sloped area being considered rough, while a surface with many small
elevation changes (like very coarse sandpaper) woul be smooth. Is this really
what roughness means. Instead I'm interested in deriving roughness from
slope standard deviation

I'm not the first person to do this, I think Grohmann et al. 2010 was
(10.1109/TGRS.2010.2053546)
"""

import rasterio as rs
import numpy as np
from scipy import ndimage

def slope_stdev(dem, neighborhood=3):
    # DEM is a 2D array of elevation values, neighborhood indicates the size of
    # the square neighborhood for slope variance calculations
    # i.e. neighborhood = 3 means a 3x3 neighborhood
    gradX, gradY = np.gradient(dem)
    slope = np.sqrt(gradX ** 2 + gradY ** 2)
    slopeMean = ndimage.uniform_filter(slope,neighborhood)
    slopeSqrMean = ndimage.uniform_filter(slope**2,neighborhood)
    slopeVar = slopeSqrMean - slopeMean**2
    slopeStdev = np.sqrt(np.absolute(slopeVar)) #In perfectly flat areas where
    #variance is ideally zero, float precision can result in a number slightly
    #below zero. Using the absolute value of variance prevents nonreal results
    return slopeStdev

def sd_slope(input_path, output_path, neighborhood=3, interpMethod='linear'):
    dataset = rs.open(input_path)
    band1 = dataset.read(1)
    kwds = dataset.profile
    slopeStdev = slope_stdev(band1,neighborhood)

    kwds['dtype'] = slopeStdev.dtype
    with rs.open(output_path, 'w', **kwds) as dst:
        dst.write(slopeStdev, indexes=1)
    return


import numpy as np
from scipy.special import iv

def tapering_window(time,D,mywindow):

	""" tapering_window returns the window for tapering a WOSA segment.
		Inputs:
		- time [1-dim numpy array of floats]: times along the WOSA segment.
		- D [float]: Temporal length of the WOSA segment.
		- mywindow [int]: Choice of tapering window:
			-> 1: Square window
			-> 2: Triangular window
			-> 3: sin window
			-> 4: sin**2 (Hanning) window
			-> 5: sin**3 window
			-> 6: sin**4 window
			-> 7: Hamming window, defined as 0.54-0.46*np.cos(2.0*np.pi*time/D)
			-> 8: 4-term Blackman-Harris window, with a0=0.35875 and a1=0.48829 and a2=0.14128 and a3=0.01168
			-> 9: Kaiser-Bessel window, with parameter alpha=2.5
			-> 10: Gaussian window, with standard dev. sigma=D/6.0
		The terminology and formulas come from:
		F. Harris. On the use of windows for harmonic analysis with the discrete fourier transform. Proceedings of the IEEE, 66(1):51-83, January 1978.
		WARNING: Provide the vector 'time' such that for all k=0,...,time.size-1, we have time[k]>=0 and time[k]<=D
		Outputs:
		- tapering_window [1-dim numpy array of floats - size=time.size]: the tapering window.
		-----------------------------
		This is part of WAVEPAL
		(C) 2016 G. Lenoir"""

	T=time.size
	if mywindow==1:
		tapering_window=np.ones(T)
	elif mywindow==2:
		tapering_window=1.0-np.absolute(time-D/2.0)/(D/2.0)
	elif mywindow==3:
		tapering_window=np.sin(np.pi*time/D)
	elif mywindow==4:
		tapering_window=(np.sin(np.pi*time/D))**2
	elif mywindow==5:
		tapering_window=(np.sin(np.pi*time/D))**3
	elif mywindow==6:
		tapering_window=(np.sin(np.pi*time/D))**4
	elif mywindow==7:
		tapering_window=0.54-0.46*np.cos(2.0*np.pi*time/D)
	elif mywindow==8:
		a0=0.35875
		a1=0.48829
		a2=0.14128
		a3=0.01168
		tapering_window=a0-a1*np.cos(2.0*np.pi*time/D)+a2*np.cos(4.0*np.pi*time/D)-a3*np.cos(6.0*np.pi*time/D)
	elif mywindow==9:
		alpha=2.5
		tapering_window=iv(0,np.pi*alpha*np.sqrt(1.0-((time-D/2.0)/(D/2.0))**2))
	elif mywindow==10:
		sig=D/6.0
		tapering_window=np.exp(-(time-D/2.0)**2/2.0/sig**2)
	else:
		print "Error: The window number you entered is not valid. Check input variable 'mywindow'."
		return
	return tapering_window