"""
Filename:     calc_fourier_transform.py
Author:       Damien Irving, irving.damien@gmail.com
Description:  Calculate Fourier transform

"""

# Import general Python modules

import sys, os, pdb
import argparse
import numpy, math
import xarray
from scipy import fftpack
from scipy import signal
from copy import deepcopy

# Import my modules

cwd = os.getcwd()
repo_dir = '/'
for directory in cwd.split('/')[1:]:
    repo_dir = os.path.join(repo_dir, directory)
    if directory == 'climate-analysis':
        break

modules_dir = os.path.join(repo_dir, 'modules')
sys.path.append(modules_dir)

try:
    import general_io as gio
    import convenient_universal as uconv
except ImportError:
    raise ImportError('Must run this script from anywhere within the climate-analysis git repo')

# Define functions

def filter_signal(signal, indep_var, min_freq, max_freq, exclusion, real=False):
    """Filter a signal by performing a Fourier Tranform and then
    an inverse Fourier Transform for a selected range of frequencies"""

    sig_fft, sample_freq = fourier_transform(signal, indep_var)
    filtered_signal = inverse_fourier_transform(sig_fft, sample_freq, min_freq=min_freq, max_freq=max_freq, exclude=exclusion)

    if real:
        filtered_signal = filtered_signal.real

    return filtered_signal

def fourier_transform(signal, indep_var):
    """Calculate the Fourier Transform.

    Args:
      signal (numpy.ndarray): Data to be transformed
      indep_var (list/tuple): Independent variable (i.e. 1 dimensional time axis or longitude axis)

    Returns:
      sig_fft (numpy.ndarray): Coefficients obtained from the Fourier Transform
      freqs (numpy.ndarray): Wave frequency associated with each coefficient

    """

    spacing = indep_var[1] - indep_var[0]
    sig_fft = fftpack.fft(signal)
    sample_freq = fftpack.fftfreq(len(indep_var), d=spacing) * len(indep_var) * spacing  #units = cycles per length of domain
    sample_freq = numpy.resize(sample_freq, sig_fft.shape)

    return sig_fft, sample_freq

def inverse_fourier_transform(coefficients, sample_freq,
                              min_freq=None, max_freq=None, exclude='negative'):
    """Inverse Fourier Transform.

    Args:
      coefficients (numpy.ndarray): Coefficients obtained from the Fourier Transform
      sample_freq (numpy.ndarray): Wave frequency associated with each coefficient
      max_freq, min_freq (float, optional): Exclude values outside [min_freq, max_freq]
        frequency range. (Note that this filtering keeps both the positive and
        negative half of the spectrum)
      exclude (str, optional): Exclude either the 'positive' or 'negative'
        half of the Fourier spectrum. (A Hilbert transform, for example, excludes
        the negative part of the spectrum)

    """

    assert exclude in ['positive', 'negative', None]

    coefs = deepcopy(coefficients)  # Deep copy to prevent side effects
                                    # (shallow copy not sufficient for complex
                                    # things like numpy arrays)

    if exclude == 'positive':
        coefs[sample_freq > 0] = 0
    elif exclude == 'negative':
        coefs[sample_freq < 0] = 0

    if (max_freq == min_freq) and max_freq:
        coefs[numpy.abs(sample_freq) != max_freq] = 0

    if max_freq:
        coefs[numpy.abs(sample_freq) > max_freq] = 0

    if min_freq:
        coefs[numpy.abs(sample_freq) < min_freq] = 0

    result = fftpack.ifft(coefs)

    return result

def first_localmax_index(data):
    """Return index of first local maxima.

    If there is no local maxima (e.g. if all the values are zero),
    it will simply return zero.

    """
    localmax_indexes = signal.argrelextrema(data, numpy.greater, mode='wrap')

    if localmax_indexes[0].size > 0:
        return localmax_indexes[0][0]
    else:
        return 0

def _get_coefficients(data, lon_axis,
                      min_freq, max_freq,
                      long_name, units,
                      outdata_dict):
    """Calculate magnitude and phase coefficients for each frequency."""

    exclusion = None
    for freq in range(min_freq, max_freq + 1):
        filtered_signal = numpy.apply_along_axis(filter_signal, -1,
                                                 data, lon_axis,
                                                 freq, freq,
                                                 exclusion, real=True)

        localmax_vals = numpy.max(filtered_signal, axis=-1)
        localmax_indexes = numpy.apply_along_axis(first_localmax_index, -1, filtered_signal)
        localmax_lons = map(lambda x: lon_axis[x], localmax_indexes)

        outdata_dict['wave'+str(freq)+'_amp'] = (localmax_vals, _coefficient_atts('amp', freq, long_name, units))
        outdata_dict['wave'+str(freq)+'_phase'] = (localmax_lons, _coefficient_atts('phase', freq, long_name, units))

    return outdata_dict

def _coefficient_atts(ctype, freq, orig_long_name, units):
    """Get the attributes for the coefficient output variable."""

    assert ctype in ('amp', 'phase')

    method = 'filtered'
    if ctype == 'amp':
        name = 'amplitude_of_'+method+'_'+orig_long_name
    elif ctype == 'phase':
        name = 'first_local_maxima_of_'+method+'_'+orig_long_name,

    atts = {'standard_name': name,
            'long_name': name,
            'units': units,
            'notes': _get_filter_text(method, freq, freq)}

    return atts

def extract_data(dset, inargs):
    """Extract the data from the input file."""

    subset_dict = gio.get_subset_kwargs(inargs)
    darray = dset[inargs.var].sel(**subset_dict)

    long_name = str(darray.attrs['long_name'])
    units = str(darray.attrs['units'])

    if inargs.avelat:
        darray = darray.mean('latitude')

    assert darray.dims[-1] == 'longitude', \
    'This script is setup to perform the fourier transform along the longitude axis'

    if inargs.valid_lon:
        start_lon, end_lon = inargs.valid_lon
        lon_vals = numpy.array([start_lon, end_lon, darray['longitude'].values.min()])
        assert numpy.sum(lon_vals >= 0) == 3, "Longitudes must be 0 to 360"
        darray.loc[dict(longitude=slice(0, start_lon))] = 0
        darray.loc[dict(longitude=slice(end_lon, 360))] = 0

    return darray, long_name, units

def _filter_data(data, lon_axis,
                 min_freq, max_freq,
                 var, long_name, units,
                 outtype, outdata_dict):
    """Filter data.

    Can perform either a hilbert transform (i.e. inverse Fourier transform
    for wavenumbers of interest) or go one step further and calculate the
    wave envelope.

    """

    assert outtype in ['envelope', 'hilbert']

    if outtype == 'envelope':
        exclusion = 'negative'
        method_short = 'env'
        method_long = 'wave_envelope'
    elif outtype == 'hilbert':
        exclusion = None
        method_short = 'ift'
        method_long = 'inverse_fourier_transformed'

    outdata = numpy.apply_along_axis(filter_signal, -1,
                                     data, lon_axis,
                                     min_freq, max_freq,
                                     exclusion)
    if outtype == 'envelope':
        outdata = 2 * numpy.abs(outdata)
    else:
        outdata = outdata.real

    filter_text = _get_filter_text(method_long, min_freq, max_freq)
    atts = {'standard_name': method_long+'_'+long_name,
            'long_name': method_long+'_'+long_name,
            'units': units,
            'notes': filter_text}

    outdata_dict[method_short+var] = (outdata, atts)

    return outdata_dict

def _get_filter_text(method, min_freq, max_freq):
    """Get the notes attribute text according to the analysis
    method and frequency range."""

    filter_text = '%s with frequency range: %s to %s' %(method, min_freq, max_freq)

    return filter_text

def spectrum(signal_fft, freqs, scaling='amplitude', variance=None):
    """Calculate the spectral density for a given Fourier Transform.

    Args:
      signal_fft, freqs (numpy.ndarray): Typically the output of fourier_transform()
      scaling (str, optional): Choices for the amplitude scaling for each frequency
        are as follows (see Wilks 2011, p440):
         'amplitude': no scaling at all (C)
         'power': sqaure the amplitude (C^2)
         'R2': variance explained = [(n/2)*C^2] / (n-1)*variance^2,
         where n and variance are the length and variance of the
         orignal data series (R2 = the proportion of the variance
         explained by each harmonic)

    """

    assert scaling in ['amplitude', 'power', 'R2']
    if scaling == 'R2':
        assert variance, \
        "To calculate variance explained must provide variance value"

    if len(signal_fft.shape) > 1:
        print "WARNING: Ensure that frequency is the final axis"

    # Calculate the entire amplitude spectrum
    n = signal_fft.shape[-1]
    amp = numpy.abs(signal_fft) / n

    # The positive and negative half are identical, so just keep positive
    # and double its amplitude
    freq_limit_index = int(math.floor(n / 2))
    pos_amp = 2 * numpy.take(amp, range(1, freq_limit_index), axis=-1)
    pos_freqs = numpy.take(freqs, range(1, freq_limit_index), axis=-1)

    if scaling == 'amplitude':
        result = pos_amp
    elif scaling == 'power':
        result = (pos_amp)**2
    elif scaling == 'R2':
        result = ((n / 2) * (pos_amp**2)) / ((n - 1) * (variance))

    return result, pos_freqs

def count_sign_change(data):
    """Count the number of times the data series changes sign.

    Works by determining the sign of all the values (-1, 0 or 1)
      and then replaces zeros with the next non-zero value, since
      -1 to/from 0 or 1 to/from 0 changes do not count as a sign
      change in this context.

    """

    assert data.ndim == 1, "Input array must be one dimensional"

    signs = numpy.sign(data)

    counter = -2
    while signs[-1] == 0:
        signs[-1] = signs[counter]
        counter = counter - 1

    for i in range(len(signs)):
        counter = 1
        while signs[i] == 0:
            signs[i] = signs[i+counter]
            counter = counter + 1

    diffs = numpy.abs(numpy.diff(signs))
    change_count = numpy.sum(diffs == 2)

    return change_count

def _get_sign_change(data, outdata_dict):
    """ """

    sign_change_data = numpy.apply_along_axis(count_sign_change, -1, data)

    sign_change_atts = {'standard_name': 'sign_change_count',
                        'long_name': 'sign_change_count',
                        'units': '',
                        'notes': 'count of number of times signal sign (pos/neg) changed'}

    outdata_dict['sign_count'] = (sign_change_data, sign_change_atts)

    return outdata_dict

def _get_env_max(data, lon_axis,
                 min_freq, max_freq,
                 units, outdata_dict):
    """Get the maximum envelope value."""

    outdata = numpy.apply_along_axis(filter_signal, -1,
                                     data, lon_axis,
                                     min_freq, max_freq,
                                     'negative')
    outdata = numpy.max(2 * numpy.abs(outdata), axis=-1)

    method_note = 'maximum value of wave envelope'
    filter_text = _get_filter_text(method_note, min_freq, max_freq)
    atts = {'standard_name': 'envelope_maximum',
            'long_name': 'envelope_maximum',
            'units': units,
            'notes': filter_text}

    outdata_dict['env_max'] = (outdata, atts)

    return outdata_dict

def main(inargs):
    """Run the program."""

    # Read the data
    dset_in = xarray.open_dataset(inargs.infile)
    gio.check_xarrayDataset(dset_in, inargs.var)
    darray, long_name, units = extract_data(dset_in, inargs)

    # Perform task
    outdata_dict = {}
    if inargs.outtype == 'coefficients':
        outdata_dict = _get_coefficients(darray.values, darray['longitude'].values,
                                         inargs.min_freq, inargs.max_freq,
                                         long_name, units, outdata_dict)
        if inargs.sign_change:
            outdata_dict = _get_sign_change(darray.values, outdata_dict)

        if inargs.env_max:
            env_max_min_freq, env_max_max_freq = inargs.env_max
            outdata_dict = _get_env_max(darray.values, darray['longitude'].values,
                                        env_max_min_freq, env_max_max_freq,
                                        units, outdata_dict)
        dims = darray.dims[:-1]
    else:
        outdata_dict = _filter_data(darray.values, darray['longitude'].values,
                                    inargs.min_freq, inargs.max_freq,
                                    inargs.var, long_name, units,
                                    inargs.outtype, outdata_dict)
        dims = darray.dims

    # Write the output file
    d = {}
    for dim in dims:
        d[dim] = darray[dim]

    for outvar in outdata_dict.keys():
        d[outvar] = (dims, outdata_dict[outvar][0])

    dset_out = xarray.Dataset(d)

    for outvar in outdata_dict.keys():
        dset_out[outvar].attrs = outdata_dict[outvar][1]

    gio.set_global_atts(dset_out, dset_in.attrs, {inargs.infile: dset_in.attrs['history'],})
    dset_out.to_netcdf(inargs.outfile)

if __name__ == '__main__':

    extra_info ="""
example (vortex.earthsci.unimelb.edu.au):
    /usr/local/uvcdat/1.5.1/bin/cdat calc_fourier_transform.py
    va_Merra_250hPa_30day-runmean-Jun2002_r360x181.nc va test.nc
    --filter 2 9 --outtype hilbert
author:
    Damien Irving, d.irving@student.unimelb.edu.au
notes:
    Note that the Hilbert transform excludes the negative half
    of the frequency spectrum and doubles the final amplitude. This does not
    give the same result as if you simply retain the negative half.
references:
    http://docs.scipy.org/doc/numpy/reference/routines.fft.html
    http://gribblelab.org/scicomp/09_Signals_sampling_filtering.html

"""

    description='Perform Fourier Transform along lines of constant latitude'
    parser = argparse.ArgumentParser(description=description,
                                     epilog=extra_info,
                                     argument_default=argparse.SUPPRESS,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument("infile", type=str, help="Input file name")
    parser.add_argument("var", type=str, help="Input file variable")
    parser.add_argument("outfile", type=str, help="Output file name")
    parser.add_argument("min_freq", type=int, help="Minimum frequency to retain")
    parser.add_argument("max_freq", type=int, help="Maximum frequency to retain (can equal min_freq for single freq)")
    parser.add_argument("outtype", type=str, choices=('hilbert', 'coefficients', 'envelope'),
                        help="Output can be a hilbert transform (i.e. inverse Fourier transform), wave envelope or magnitude and phase coefficients for each freq")

    parser.add_argument("--latitude", type=float, nargs=2, metavar=('START', 'END'),
                        help="Latitude range over which to perform Fourier Transform [default = entire]")
    parser.add_argument("--valid_lon", type=float, nargs=2, metavar=('START', 'END'), default=None,
                        help="Longitude range over which to perform Fourier Transform (all other values are set to zero) [default = entire]")
    parser.add_argument("--time", type=str, nargs=2, metavar=('START_DATE', 'END_DATE'),
                        help="Time period [default = entire]")

    parser.add_argument("--avelat", action="store_true", default=False,
                        help="Average the data over the latitude axis before performing Fourier transform")

    parser.add_argument("--sign_change", action="store_true", default=False,
                        help="for a coefficients outtype, add an extra output variable which represents the count of times the signal changes sign")
    parser.add_argument("--env_max", type=int, nargs=2, metavar=('MIN_FREQ', 'MAX_FREQ'), default=None,
                        help="for a coefficients outtype, add an extra output variable for the maximum envelope value")

    args = parser.parse_args()

    print 'Input files: ', args.infile
    print 'Output file: ', args.outfile

    main(args)


import numpy as np

from . import solve
from . factorization_QR import transform_Householder, retrieve_H

def power_method(A, u0=None, displace=0, max_step=10000, tolerance=1e-8, verbose=False, inverse=False, normalize=True):
    # power_method: return largest modulus eigenvalue and corresponding eigenvector
    # inverse = True: return smallest eig instead.
    m, n = A.shape
    assert m == n

    if u0 is None:
        u0 = np.ones(n)
    if displace != 0:
        A = A - displace * np.eye(m)

    u = u0
    step = 0
    while True:
        old_u = np.copy(u)

        if not inverse:
            y = A @ u
        else:
            # TODO: since A is fixed, we can save the LU decomposition and reuse to reduce computation.
            y = solve(A, u, method="PLU")

        mu = u[np.argmax(np.abs(u))]
        u = y / mu

        step += 1
        if step >= max_step:
            if verbose:
                print(f"Early stop at step {step}")
            break

        if np.linalg.norm(old_u-u, ord=1) < tolerance:
            if verbose:
                print(f"Covengent at step {step} under tolerance {tolerance}")
            break

    if inverse:
        mu = 1 / mu

    if displace != 0:
        mu += displace

    if normalize:
        u = u / np.linalg.norm(u, ord=np.inf)

    return mu, u

def eig_power(A):
    # return all eigenvalues and eigenvectors
    m, n = A.shape
    assert m == n

    mus = []
    us = []

    X = np.copy(A)
    for i in range(n):
        mu, u = power_method(X)

        mus.append(mu)
        us.append(u)

        H = retrieve_H(*transform_Householder(u))
        X = H @ X @ H
        X = X[1:, 1:]

    return mus, us


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

# In[491]:

import matplotlib.pyplot as plt
# ^^^ pyforest auto-imports - don't write above this line
import numpy as np
import pathlib
from skimage import color
import random

# In[253]:

defaultPath = r'G:\Documents\ReferenceBooks\1-DigitalImageProcessing\HW3\Images\\'

# ### Convert image to FFT

# In[362]:

class GrayImageFFT:
    def load_gray_from_file(self,defaultPath,fileName):
        self.image = plt.imread(defaultPath+fileName)
        self.image = color.rgb2gray(self.image)

    def load_from_array(self,array):
        self.image = array

    def fft(self):
        self.fft=np.fft.fft2(self.image)
        self.fft = np.fft.fftshift(self.fft)
        self.magnitude = 20*np.log(np.abs(self.fft))

        self.filtered = self.fft
        return self.magnitude

    def apply_filter(self,custom_filter):
        self.filtered = self.filtered*custom_filter

    def get_filtered_image(self):
        shifted= np.fft.ifftshift(self.filtered)
        return np.abs( np.fft.ifft2(shifted))

# ### Notch Filter

# In[335]:

def get_filter_from_point(shape,d0,u,v):
    length = shape[0]
    width = shape[1]
    my_array=np.indices((length,width))
    distance_uv = np.sqrt((my_array[0] -length/2 + u)**2 + (my_array[1]-width/2+v)**2)
    distance_muv = np.sqrt((my_array[0] -length/2 - u)**2 + (my_array[1]-width/2-v)**2)
    bandpass_filter= np.logical_or(distance_uv<=d0,distance_muv<=d0)
    notch_filter = np.invert( bandpass_filter)
    return notch_filter

# In[336]:

imagefft=GrayImageFFT()
imagefft.load_gray_from_file(defaultPath,'Vessel.png')

imagefft.fft()

H1 = get_filter_from_point(vessel.shape,  3,180, 128)
H2 = get_filter_from_point(vessel.shape, 3,-180, 128)
H3 = get_filter_from_point(vessel.shape, 3, 58, 128)
H4 = get_filter_from_point(vessel.shape, 3, -58, 128)
H5 = get_filter_from_point(vessel.shape,2,120,128)
H6 = get_filter_from_point(vessel.shape,2,-120,128)

NotchFilter = H1*H2*H3*H4*H5*H6

imagefft.apply_filter(NotchFilter)
back_image = imagefft.get_filtered_image()

plt.figure(figsize=(10,10))
plt.subplot(2,2,1)
plt.imshow(dft,cmap='gray')

plt.subplot(2,2,2)
plt.imshow(imagefft.magnitude*NotchFilter,cmap='gray')

plt.subplot(2,2,3)
plt.imshow(vessel,cmap='gray')

plt.subplot(2,2,4)
plt.imshow(back_image,cmap='gray')

plt.imsave(defaultPath+'VesselDFTAfterFix.png',imagefft.magnitude*NotchFilter,cmap='gray')
plt.imsave(defaultPath+'VesselDFT.png',imagefft.magnitude,cmap='gray')
plt.imsave(defaultPath+'VesselNotchFilter.png',back_image,cmap='gray')

# ### Gaussian Smoothing Filtering

# In[332]:

def gaussian_lowpass_filter(shape,sigma):
    indices=np.indices(dimensions=shape)
    distance=np.sqrt((indices[0]-shape[0]/2)**2+(indices[1]-shape[1]/2)**2)
    return np.exp(-1*distance**2/(2*sigma**2))

# In[367]:

nature=plt.imread(defaultPath+'Nature.jpg')

guassian = gaussian_lowpass_filter((nature.shape[0],nature.shape[1]),5)

nature_array = []
for i in range(3):
    imageDim0 = GrayImageFFT()
    imageDim0.load_from_array(nature[:,:,i])
    imageDim0.fft()
    imageDim0.apply_filter(guassian)
    nature_array.append(imageDim0.get_filtered_image())

gaussian_nature = np.zeros(nature.shape)
gaussian_nature[:,:,0] = nature_array[0]
gaussian_nature[:,:,1] = nature_array[1]
gaussian_nature[:,:,2] = nature_array[2]
gaussian_nature = (gaussian_nature-gaussian_nature.min())/(gaussian_nature.max()-gaussian_nature.min())

plt.figure(figsize=(12,12))
plt.subplot(2,2,1)
plt.imshow(nature)
plt.subplot(2,2,2)
plt.imshow(gaussian_nature)

plt.imsave(defaultPath+'NatureBlur.jpg',gaussian_nature)

# ### Gaussian Deblur

# In[386]:

nature=plt.imread(defaultPath+'NatureBlur.jpg')

gauss =1/(1e-1+gaussian_lowpass_filter((nature.shape[0],nature.shape[1]),5))

nature_array = []
for i in range(3):
    imageDim0 = GrayImageFFT()
    imageDim0.load_from_array(nature[:,:,i])
    imageDim0.fft()
    imageDim0.apply_filter(guassian)
    nature_array.append(imageDim0.get_filtered_image())

gaussian_nature = np.zeros(nature.shape)
gaussian_nature[:,:,0] = nature_array[0]
gaussian_nature[:,:,1] = nature_array[1]
gaussian_nature[:,:,2] = nature_array[2]
gaussian_nature = (gaussian_nature-gaussian_nature.min())/(gaussian_nature.max()-gaussian_nature.min())

plt.figure(figsize=(12,12))
plt.subplot(1,2,1)
plt.imshow(nature)
plt.subplot(1,2,2)
plt.imshow(gaussian_nature)

plt.imsave(defaultPath+'NatureDeblur.jpg',gaussian_nature)

# ### White Noise or Random Noise

# In[504]:

def random_noise(image,noise_percentage,saltPercent):
    img_noise = np.copy(image)
    noise_num = np.int(np.round(noise_percentage * img_noise.size))
    x=np.random.randint(0,img_noise.shape[0],noise_num)
    y=np.random.randint(0,img_noise.shape[1],noise_num)

    salt_vs_pepper = np.random.binomial(1,saltPercent,size=noise_num)*255
    img_noise[x,y,0] = salt_vs_pepper
    img_noise[x,y,1] = salt_vs_pepper
    img_noise[x,y,2] = salt_vs_pepper
    return img_noise

# In[505]:

def median_filter(data):
    new_image = np.zeros(data.shape)
    for k in range(0,data.shape[2]):
        for i in range(1, data.shape[0]-1):
            for j in range(1, data.shape[1]-1):
                temp = [
                   data[i-1, j-1,k],
                   data[i-1, j,k],
                   data[i-1, j + 1,k],
                   data[i, j-1,k],
                   data[i, j,k],
                   data[i, j + 1,k],
                   data[i + 1, j-1,k],
                   data[i + 1, j,k],
                   data[i + 1, j + 1,k]]
                temp = sorted(temp)
                new_image[i, j,k]= temp[4]
    return new_image

# In[514]:

airplane=plt.imread(defaultPath+'Airplane.jpg')
noisy_image = random_noise(airplane,0.05,1)
denoise_image = median_filter(median_filter(noisy_image))

plt.figure(figsize=(15,15))
plt.subplot(1,2,1)
plt.imshow(noisy_image)
plt.subplot(1,2,2)
plt.imshow(denoise_image/255)

plt.imsave(defaultPath+'Airplane_WhiteNoise.jpg',noisy_image)
plt.imsave(defaultPath+'Airplane_WhiteNoise_Fixed.jpg',denoise_image/255)

# ### Salt And Pepper Noise

# In[515]:

airplane=plt.imread(defaultPath+'Airplane.jpg')
noisy_image = random_noise(airplane,0.05,0.4)
denoise_image = median_filter(median_filter(noisy_image))

plt.figure(figsize=(15,15))
plt.subplot(1,2,1)
plt.imshow(noisy_image)
plt.subplot(1,2,2)
plt.imshow(denoise_image/255)

plt.imsave(defaultPath+'Airplane_SaltPepperNoise.jpg',noisy_image)
plt.imsave(defaultPath+'Airplane_SaltPepperNoise_Fixed.jpg',denoise_image/255)

# ### Histogram Matching

# In[627]:

def histogram_matching(src, image):
    old_shape = src.shape
    source = src.ravel()
    image = image.ravel()

    source_values, index, source_counts = np.unique(src, return_inverse=True,return_counts=True)
    image_values, image_counts = np.unique(image, return_counts=True)

    s_cum = np.cumsum(source_counts).astype(np.float64)
    s_cum /= s_cum[-1]
    t_cum = np.cumsum(image_counts).astype(np.float64)
    t_cum /= t_cum[-1]

    intercept_result = np.interp(s_cum, t_cum, image_values)

    return interp_t_values[index].reshape(oldshape)

# In[628]:

imageref=eyeref=plt.imread(defaultPath+'eyeref.png')
imageref = np.round(color.rgb2gray(imageref)*255)

image2=plt.imread(defaultPath+'eye.png')
image2 = np.round(color.rgb2gray(image2)*255)

matched = hist_match(image2,imageref)

plt.figure(figsize=(15,15))
plt.subplot(1,3,1)
plt.imshow(image2,cmap='gray')
plt.title('Source Image')

plt.subplot(1,3,2)
plt.imshow(imageref,cmap='gray')
plt.title('ReferenceImage')

plt.subplot(1,3,3)
plt.imshow(matched,cmap='gray')
plt.title('FixedImage')

plt.imsave(defaultPath+'EyeHistogram.png',matched)

# In[ ]:

# In[ ]:

# In[ ]:


import math
import pylab
import scipy.optimize
plot = pylab.plot
legend = pylab.legend

def f1(x):
    """ Computes and returns f1(x). """
    return math.cos(2.0 * x * math.pi) * math.exp(- x ** 2)

def f2(x):
    """ Computes and returns f2(x). """
    return math.log(x + 2.2)

def f3(x):
    """ Computes and returns f1(x) - f2(x). """
    return f1(x) - f2(x)

def create_plot_data(f, xmin, xmax, n):
    """
    Computes and returns values of y = f(x).

    f -- function of x
    xmin -- minimum value of x
    xmax -- maximum value of x
    n -- number of values of x

    returns values of x and y
    """
    xs = []
    ys = []
    for i in range(n):
        xi = xmin + float(i) * (xmax - xmin) / (n - 1)
        yi = f(xi)
        xs.append(xi)
        ys.append(yi)
    return (xs, ys)

def myplot():
    """ Plots f1 and f2, displays graph, saves pdf and png, returns None. """
    data1 = create_plot_data(f1, -2, 2, 1001)
    data2 = create_plot_data(f2, -2, 2, 1001)
    plot(data1[0], data1[1], label="f1")
    plot(data2[0], data2[1], label="f2")
    pylab.xlabel("x")
    legend()
    pylab.savefig("plot.png")
    pylab.savefig("plot.pdf")
    return None

def find_cross():
    """ Computes and returns an approximate root of f1(x) - f2(x) = 0 """
    return scipy.optimize.brentq(f3, 0.091, 0.093)


import math
import numpy as np
from tqdm import tqdm
from .base import BaseModel

class Perceptron(BaseModel):

    def __init__(self, epochs=1000, learning_rate=0.1, random_seed=1):
        self.weights = None
        self.bias = None
        self.epochs = epochs
        self.learning_rate = learning_rate
        self.seed = random_seed
        self.loss = []

    def _init_weights(self, n_features):
        """Randomly initialize weights and bias. Parameters will be set to random
            values between [-1/sqrt(N), 1/sqrt(N)].

            Args:
                n_features (int): number of input features
        """
        limit = 1 / math.sqrt(n_features)
        random_gen = np.random.RandomState(self.seed)
        # uniform initializations is arbitrary,
        # you may try different ones like normal
        self.weights = random_gen.uniform(-limit, limit, (n_features,))
        self.bias = random_gen.uniform(-limit, limit, (1,))

    def fit(self, X, Y):
        """Fit model on X and Y training data

        Args:
            X (np.array): input, shape (n_samples, n_features)
            Y (np.array): output, shape (n_samples)
        """
        n_features = X.shape[1]
        self._init_weights(n_features)

        for _ in tqdm(range(self.epochs)):
            # feedforward and predict
            output = self._forward(X)

            # compare
            errors = (Y - output)

            # update weight and bias
            gradient_weights = np.dot(errors, X)
            self.weights += self.learning_rate * gradient_weights
            gradient_bias = np.sum(errors)
            self.bias += self.learning_rate * gradient_bias

            self.loss.append(self.sum_squared_error(Y, output))

    def linear(self, Z):
        """Activation function. return Z.
            Very redudant, but here to be
            consistent with the rest of the framework

        Args:
            Z (np.array): shape (n_features)

        Returns:
            (np.array): shape (n_features)
        """
        return Z

    def sum_squared_error(self, actual, predicted):
        """sum of squared error

            sum(error^2)/2

        Args:
            actual (np.array): shape, (n_features)
            predicted (np.array): shape, (n_features)

        Returns:
            float: mse error value
        """
        return np.sum(np.square(actual - predicted)) / 2.0

    def _forward(self, X):
        """returns feedforward prediction

        Args:
            X (np.array): shape (n_samples, n_features)

        Returns:
            (np.array): shape (n_samples)
        """
        # (n_samples, n_features) x (n_features,)
        # feedforward, shape (n_samples,)
        output = np.dot(X, self.weights) + self.bias
        # pass feedforward results to activation function
        output = self.linear(output)
        return output

    def predict(self, X):
        """returns binary classification prediction. using the
            step function.

            1 if X > 0.0
            0 if X < 0.0

        Args:
            X (np.array): shape (n_samples, n_features)

        Returns:
            np.array: shape (n_samples,)
        """
        return np.where(self._forward(X) > 0.0, 1, 0)


from math import sqrt, floor, log

import numpy as np

from numba import jit

@jit(nopython=False, cache=True)
def trial_division_method(limit):
    '''
    Inputs:

    limit -- positive integer, required amount of first consecutive prime numbers

    Returns an integer, the sum of all first prime numbers.
    '''

    founded = 6

    if limit < founded:
        return sum((2, 3, 5, 7, 11, 13)[:limit])

    total = sum((2, 3, 5, 7, 11, 13))

    # Initialize candidate to odd number
    candidate = 13

    while founded < limit:

        # Test only odd numbers
        candidate += 2

        for num in range(3, floor(sqrt(candidate)) + 1, 2):
            if candidate % num is 0:
                break
        else:
            total += candidate
            founded += 1

    return total

@jit(nopython=False, cache=True)
def factor_division_method(limit):
    '''
    Inputs:

    limit
    -- integer, required amount of first consecutive prime numbers
    -- must be greater than or equal to 6

    Returns an integer, the sum of all first prime numbers.
    '''

    # Exploit the fact that every composite number has prime factors
    # that are smaller than the number itself. If the numer does not
    # have prime factors, it must be prime.

    # Leave the only even prime number for the end and focus on odd numbers
    limit -= 1

    founded = 5

    primes = np.zeros(shape=limit, dtype=np.uint32)

    primes[:founded] = (3, 5, 7, 11, 13)

    # Initialize candidate to odd number
    candidate = 13

    while founded < limit:

        # Test only odd numbers
        candidate += 2

        maxnum = floor(sqrt(candidate)) + 1

        for num in primes:
            if candidate % num is 0:
                break
            elif num > maxnum:
                primes[founded] = candidate
                founded += 1
                break

    # Now it is time to include numer two
    return np.sum(primes) + 2

@jit(nopython=False, cache=True)
def ambi_sieve(n):
    '''
    Input:

    n
    -- integer, upper bound of a range
    -- must be greater than or equal to 6

    Returns 1D numpy array of integers, all prime numbers
    between 2 (inclusive) and n (exclusive).

    This algorithm is from https://stackoverflow.com/a/2068548
    and is originally written for Python 2.

    Minor changes to the code were made to adjust it to Python 3.
    '''

    sieve = np.arange(3, n, 2, dtype=np.uint32)

    for m in range(3, floor(sqrt(n)) + 1, 2):
        if sieve[(m - 3) // 2]:
            sieve[(m * m - 3) // 2::m] = 0

    return np.r_[2, sieve[sieve > 0]]

@jit(nopython=False, cache=True)
def primesfrom2to(n):
    '''
    Input:

    n
    -- integer, upper bound of a range
    -- must be greater than or equal to 6

    Returns 1D numpy array of integers, all prime numbers
    between 2 (inclusive) and n (exclusive).

    This algorithm is from https://stackoverflow.com/a/2068548
    and is originally written for Python 2.

    Minor changes to the code were made to adjust it to Python 3.
    '''

    sieve = np.ones(n // 3 + (n % 6 == 2), dtype=np.bool)

    for i in range(1, floor(sqrt(n)) + 1):
        if sieve[i]:
            k = (3 * i + 1) | 1
            sieve[k * k // 3::2 * k] = False
            sieve[k * (k - 2 * (i & 1) + 4) // 3::2 * k] = False

    return np.r_[2, 3, (3 * np.nonzero(sieve)[0][1:] + 1) | 1]

@jit(nopython=True)
def approximate_prime(i, c=0.45):
    '''
    Inputs:

    i
    -- positive integer, i-th prime number
    -- it must be at least 20, when constant is 0.45

    c
    -- float number, constant
    -- must be greater than or equal to 0.0 and less than 1.0 (default is 0.45)
    -- minimum value for argument i depends on this constant

    Returns positive integer, an approximation of the i-th prime number
    that is greater than true i-th prime number.
    '''

    # Makes use of the prime number theorem and the Rosser's
    # theorem to narrow the upper bound.

    a = log(i)

    return floor(i * (a + log(a) - c))

Daftcode Python Level UP 2018 solutions/zadanie2/task2.py


import numpy as np
from numpy.random import rand
from math import sqrt, log
from timeit import timeit as ti

def dist1(A, B):
    # Preallocate output array.
    # Start with everything set to 0.
    D = np.zeros((A.shape[0], B.shape[0]))
    # For each row in A
    for i in xrange(A.shape[0]):
        # For each row in B
        for j in xrange(B.shape[0]):
            # For corresponding entries of
            # the rows in A and B
            for k in xrange(A.shape[1]):
                # Add the squared difference.
                D[i,j] += (A[i,k] - B[j,k])**2
            # Take square root after finishing sum.
            D[i,j] = sqrt(D[i,j])
    return D

def dist2(A, B):
    # Preallocate output array.
    # This time we'll be overwriting it,
    # so there's no need to assign it values.
    D = np.empty((A.shape[0], B.shape[0]))
    # For each row in A
    for i in xrange(A.shape[0]):
        # For each row in B
        for j in xrange(B.shape[0]):
            # Take the distance between the rows
            D[i,j] = sqrt(((A[i] - B[j])**2).sum())
    return D

def dist3(A, B):
    # Preallocate output array
    D = np.empty((A.shape[0], B.shape[0]))
    # For each row in A
    for i in xrange(A.shape[0]):
        # Take distance from this row to each row in B.
        D[i] = np.sqrt(((A[i] - B)**2).sum(axis=1))
    return D

def dist4(A, B):
    # Use the fact that
    # (a-b)**2 = a**2 + b**2 - 2*a*b
    # Take squares of A and B.
    # Reshape so broadcasting works later
    A2 = (A**2).sum(axis=1).reshape((-1,1))
    B2 = (B**2).sum(axis=1).reshape((1,-1))
    # Use matrix multiplication to start
    # computing the remaining term.
    D = A.dot(B.T)
    # Multiply in place to avoid
    # allocating temporary arrays.
    D *= -2
    # Broadcast to add in A2 and B2.
    # Perform these operations in place.
    D += A2
    D += B2
    # Take square root without
    # allocating a temporary array.
    np.sqrt(D, out=D)
    return D

def time(sizes):
    t1 = []
    t2 = []
    t3 = []
    t4 = []
    for size in sizes:
        A = rand(size, 10)
        B = rand(size, 10)
        t1.append(ti("dist1(A, B)", setup="from __main__ import dist1, A, B", number=10))
        t2.append(ti("dist2(A, B)", setup="from __main__ import dist2, A, B", number=10))
        t3.append(ti("dist3(A, B)", setup="from __main__ import dist3, A, B", number=10))
        t4.append(ti("dist4(A, B)", setup="from __main__ import dist4, A, B", number=10))
        print size
    times = np.empty((5, len(sizes)))
    times[0] = sizes
    times[1] = t1
    times[2] = t2
    times[3] = t3
    times[4] = t4
    np.save("times.npy", times)

if __name__ == __main__:
    time([10, 50, 100, 200, 300, 400, 500, 750, 1000])


import numpy as np

"""
n-dimension grid
"""

def grid2list(grid, n):
    grid = np.array(grid)
    truedim = grid.shape
    l = np.product(truedim[:n])  # length of the list
    list = np.zeros(np.append(l, truedim[n:]))
    grid2list.index = 0

    def iterate(addr):
        if len(addr) == n:
            list[grid2list.index] = grid[tuple(addr)]
            grid2list.index += 1
        else:
            for i in range(len(grid[tuple(addr)])):
                iterate(np.append(addr, i))

    iterate(np.array([]))
    return list

def list2grid(list, dim):
    list = np.array(list)
    dim = np.array(dim)

    if len(list) != np.product(dim):
        raise Exception("Dimension of grid must match the size of the list.")

    grid = np.zeros(np.append(dim, list.shape[1:]))
    list2grid.index = 0

    def iterate(addr):
        if len(addr) == len(dim):
            grid[tuple(addr)] = list[list2grid.index]
            list2grid.index += 1
        else:
            for i in range(len(grid[tuple(addr)])):
                iterate(np.append(addr, i))

    iterate(np.array([]))
    return grid

def makegrid(init, end, dim=None, res=101):
    init = np.array(init)
    end = np.array(end)

    d = len(init)
    if dim == None:
        dim = np.ones(d) * res

    factors = (end - init) / float(res - 1)
    grid = np.zeros(np.append(dim, len(dim)))

    def iterate(addr):
        if len(addr) == len(dim):
            grid[tuple(addr)] = init + addr * factors
        else:
            for i in range(len(grid[tuple(addr)])):
                iterate(np.append(addr, i))

    iterate(np.array([]))
    return grid


# -*- coding: utf-8 -*-
"""
Created on Thu Mar 26 16:37:36 2020

@author: Philipe_Leal
"""

import numpy as np

def correlation_coefficient_pvalue(data1, data2, n_samples):

    corr_coeffs = np.empty(n_samples)
    obtained_corr = np.corrcoef(data1, data2)[0][1]

    for i in range(n_samples):

        data1_shuffled = np.random.permutation(data1)

        corr_coeffs[i] = np.corrcoef(data1_shuffled, data2)[0][1]

    p_value = np.mean( np.abs(corr_coeffs) >= np.abs(obtained_corr) )

    return {'Randomized_Pearson_Mean_Corr' : np.mean(corr_coeffs),
            'IC': np.percentile(corr_coeffs, [2.5, 97.5]),
            'pvalue': p_value}

if '__main__' == __name__:

    """Do a permutation test: Permute the series1 data values but leave the
        series 2 untouched.

       Evaluate the correlation between the permutated and the original data
       for all iterations.

       Evaluate the amount of times (in %)
       that the randomized pvalue got more extreme than the observed one.

       This percentage represents the probability of having a correlation
       more extreme than the observed one given that
       the two series are independent: therefore, have no correlation
       between themselves.

       The IC represents the thresholds that would be expected in case
       both series were independent assuming normal distribution.
       If the given returned correlation coefficient is out of that bound,
       we could assume that the data is not independent.

    """

    data1 = np.random.normal(-50,4, 100)

    data2 = np.random.normal(15, 1, 100)
    n_samples = 9999

    R = correlation_coefficient_pvalue(data1, data2, n_samples)

    print(R)


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

from numpy import linspace, zeros, exp
import matplotlib.pyplot as plt

N_0 = int(input('Give initial population size N_0: '))
r   = float(input('Give net growth rate r: '))
dt  = float(input('Give time step size: '))
N_t = int(input('Give number of steps: '))
t = linspace(0, N_t*dt, N_t+1)
N = zeros(N_t+1)

N[0] = N_0
for n in range(N_t):
    N[n+1] = N[n] + r*dt*N[n]

numerical_sol = 'bo' if N_t < 70 else 'b-'
plt.plot(t, N, numerical_sol, t, N_0*exp(r*t), 'r-')
plt.legend(['numerical', 'exact'], loc='upper left')
plt.xlabel('t')
plt.ylabel('N(t)')
filestem = 'growth1_%dsteps' % N_t
plt.savefig('%s.png' % filestem)
plt.savefig('%s.pdf' % filestem)


# File: linear.py
# Last Change: 29.10.2018
# Content: Linear Regression layout class
# Authors: Jonas Weimar,

import numpy as np

# => Simple Linear Regression Model
class SLRModel(object):

    # Initializer / Constructor:
    def __init__(self):
        self.coef = []

    # Hook methods for build in functions:
    def __str__(self):
        return "f(x) = {}x + {}".format(self.coef[0], self.coef[1])

    def __getitem__(self, key):
        return self.coef[key]

    # Public Methods
    def fit(self, x, y):
        self.coef.clear()

        n = np.size(x)
        x_mean, y_mean = np.mean(x), np.mean(y)

        ss_xy, ss_xx = np.sum(y*x - n*y_mean*x_mean), np.sum(x*x - n*x_mean*x_mean)

        m = ss_xy / ss_xx
        b = y_mean - m*x_mean

        self.coef = [m, b]

    def predict(self, x):
        result = []
        for row in x:
            result.append( (self.coef[0] * row + self.coef[1]) )
        return result


import numpy as np
from scipy.stats import kstest, ks_2samp

np.random.seed(2020)

if __name__ == "__main__":

    # np.random.normal(center, spread, size)
    x = np.random.normal(0, 1, 10)
    y = np.random.normal(0, 1, 10)
    z = np.random.normal(1.1, 0.9, 10) # one of these things is not like the other
    print("X:", x) #> [-0.14235884,  2.05722174,  0.28326194,  1.32981198, -0.15462185, -0.06903086,  0.75518049,  0.82564665, -0.11306921, -2.36783759]
    print("Y:", y) #> [-0.16704943,  0.68539797,  0.02350011,  0.45620128,  0.27049278, -1.43500814,  0.88281715, -0.58008166, -0.5015653 ,  0.59095329]
    print("Z:", z) #> [0.44154537, 1.33557992, 0.32978398, 0.93122668, 0.76386234, 0.68422613, 0.36518051, 1.05938903, 1.209195  , 1.9333575 ]

    print("--------------------------")
    print("KS TESTS (AGAINST NORMAL DISTRIBUTION)...")
    print("X:", kstest(x, "norm")) #> KstestResult(statistic=0.33855972126320677, pvalue=0.1590112941560191)
    print("Y:", kstest(y, "norm")) #> KstestResult(statistic=0.18866753744918974, pvalue=0.8060547009565138)
    print("Z:", kstest(z, "norm")) #> KstestResult(statistic=0.6292184031091476, pvalue=0.0002318573221670418)

    print("--------------------------")
    print("TWO-SAMPLE KS TESTS...")
    print("X-Y:", ks_2samp(x, y)) #> KstestResult(statistic=0.3, pvalue=0.7869297884777761)
    print("X-Z:", ks_2samp(x, z)) #> KstestResult(statistic=0.6, pvalue=0.05244755244755244)
    print("Y-Z", ks_2samp(y, z)) #> KstestResult(statistic=0.6, pvalue=0.05244755244755244)

    #breakpoint()


'''
This file implements fisher projection of classification data onto K(< no.of.classes) dimensions
to further fit it with LDA.
Referenced from
https://github.com/probml/pmtk3/blob/master/toolbox/SupervisedModels/fisherLda/fisherLdaFit.m
Author: Srikar-Reddy-Jilugu(@always-newbie161)
'''
import superimport

import numpy as np

def fisher_lda_fit(X, y, kdims):
    """
    :param X: shape(nsamples, ndims)
    :param y: shape(nsamples, 1)
    :param kdims: int
    :return W: Linear Projection Matrix; ndarray of shape(ndims, kdims)
    """
    nclasses = np.max(y)  # no .of.classes
    nsamples, ndims = X.shape

    if nclasses == 2:
        # assuming y is from {1,2}
        ndx1 = np.where(y == 1)[0]
        ndx2 = np.where(y == 2)[0]
        mu1, mu2 = np.mean(X[ndx1, :]), np.mean(X[ndx2, :])
        S1, S2 = np.cov(X[ndx1, :]), np.cov(X[ndx2, :])
        Sw = S1 + S2
        W = np.linalg.inv(Sw) @ (mu2 - mu1)
    else:
        # assuming y is from {1,2,..nclasses}
        muC = np.zeros((nclasses, ndims))
        for c in range(0, nclasses):
            ndx = np.where(y == (c + 1))[0]
            muC[c, :] = (np.mean((X[ndx, :]), axis=0))

        mu_matrix = np.squeeze(muC[y-1, :], axis=1)
        Sw = (X - mu_matrix).T @ (X - mu_matrix)
        muX = np.mean(X, axis=0)
        Sb = (np.ones((nclasses, 1))*muX - muC).T @ (np.ones((nclasses, 1))*muX - muC)
        _, eigvecs = np.linalg.eig(np.linalg.pinv(Sw) @ Sb)
        W = eigvecs[:, :kdims]

    return W


import superimport

import pyprobml_utils as pml

import matplotlib.pyplot as plt
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.decomposition import PCA
from scipy import linalg
from numpy import array
from numpy import mean
from numpy import cov
from numpy.linalg import eig
import numpy as np

# Dataset according to matlab code:

n = 100
np.random.seed(0)
a = np.random.multivariate_normal((1, 3), [[4.0, 0.01], [0.01, 0.1]], n)
b = np.random.multivariate_normal((3, 1), [[4.0, 0.01], [0.01, 0.1]], n)

X = np.vstack((a, b))

Y = np.hstack((np.zeros(n), np.ones(n)))

mu_a, mu_b = a.mean(axis=0).reshape(-1,1), b.mean(axis=0).reshape(-1,1)

xmax = np.max(X[:, 0])
xmin = np.min(X[:, 0])
ymax = np.max(X[:, 1])
ymin = np.min(X[:, 1])

nMale = 100
nFemale = 200

"""##FischerLDA
It is done in 2 ways:

a) Using sklearn.discriminant

b) According to the book (manual calculation))

# a)
"""

def flda_sklearn(X, Y):
    lda = LinearDiscriminantAnalysis()
    X_fit = lda.fit(X, Y)
    X_tran = lda.transform(X)
    w_sk = X_fit.coef_
    return X_tran, X_fit, w_sk

def Xproj_fish_sk_cal(w_sk):
    slope = w_sk[0, 1]/w_sk[0, 0]
    Xproj_fish_sk = X.dot(w_sk.T)
    return Xproj_fish_sk

"""# b)"""

def calculate_covariance_matrix(X, Y=None):
    if Y is None:
        Y = X
    n_samples = np.shape(X)[0]
    covariance_matrix = (1 / (n_samples-1)) * (X - X.mean(axis=0)).T.dot(Y - Y.mean(axis=0))

    return np.array(covariance_matrix, dtype=float)

def flda_manual(a, b):
    # Covariance matrices of the two datasets
    cov1 = calculate_covariance_matrix(a)
    cov2 = calculate_covariance_matrix(b)
    cov_tot = (cov1 + cov2)/2

    # Mean of the two datasets
    mean1 = a.mean(0)
    mean2 = b.mean(0)
    mean_diff = np.atleast_1d(mean1 - mean2)

    # The vector w, which when X is projected onto it best separates the data by class.
    # w = (mean1 - mean2) / (cov1 + cov2) [Formula in topic 9.2.6.1 in the book]

    w = -np.linalg.pinv(cov_tot).dot(mean_diff)

    return w

def Xproj_fish_man_cal(X, w):
    Xproj_fish = X.dot(w)
    Xproj_fish_male = Xproj_fish[:nMale]
    Xproj_fish_female = Xproj_fish[nMale:nFemale]
    return Xproj_fish, Xproj_fish_male, Xproj_fish_female

"""##PCA

It is done in 2 ways:

a) Using sklearn.decomposition

b) Manual principal component analysis

# a)
"""

def pca_sklearn(X, Y):
    pca = PCA(n_components=1)
    X_fit = pca.fit(X)
    X_tran = pca.transform(X)
    return X_fit, X_tran

def Xproj_pca_sk_cal(X_fit):
  weights = X_fit.components_
  Xproj_pca_sk = X.dot(weights.T)
  return Xproj_pca_sk

"""# b)"""

def pca_manual(X, Y):
    # calculate the mean of each column
    M = mean(X.T, axis=1)
    # center columns by subtracting column means
    C = M - X
    # calculate covariance matrix of centered matrix
    V = cov(C.T)
    # eigendecomposition of covariance matrix
    values, vectors = eig(V)
    # project data
    P = vectors.T.dot(C.T)

    return vectors

def Xproj_pca_man_cal(X, vectors):
  vector = vectors[:, 0]
  Xproj_pca = X.dot(vector)
  Xproj_pca_male = Xproj_pca[:nMale]
  Xproj_pca_female = Xproj_pca[nMale:nFemale]
  return Xproj_pca, Xproj_pca_male, Xproj_pca_female

"""Plot functions:"""

def plot_data(a, b):
    plt.figure()
    plt.plot(a[:,0], a[:,1], 'b.', b[:,0], b[:,1], 'r+')
    #plt.plot(mu_a, mu_b, 'black')
    plt.legend(['Male', 'Female', 'Means'])
    pml.savefig("fisher_lda_data.pdf")
    plt.show()

def plot_all_vectors(a, b, vectors, w):
    mu_a, mu_b = a.mean(axis=0).reshape(-1,1), b.mean(axis=0).reshape(-1,1)
    mid_point = (mu_a + mu_b)/2

    vector = vectors[:, 0]
    slope_pca = vector[1]/vector[0]
    c_pca = mid_point[1] - slope_pca*mid_point[0]

    slope = w[1]/w[0]
    c = mid_point[1] - slope*mid_point[0]

    x = np.linspace(xmin+1, xmax+1, 100)
    z = np.linspace(xmin+1, xmax+1, 100)

    plt.figure()
    plt.xlim(xmin, xmax)
    plt.ylim(ymin, ymax)
    plt.plot(a[:,0], a[:,1], 'b.', b[:,0], b[:,1], 'r+')
    plt.plot(x, slope*x + c)
    plt.plot(z, slope_pca*z + c_pca)
    #plt.plot(mu_a, mu_b, 'black')
    plt.legend(['Male', 'Female', 'FisherLDA vector', 'PCA vector'])
    #plt.legend(['Male', 'Female', 'FisherLDA vector', 'PCA vector', 'Means'])
    pml.savefig("fisher_lda_lines.pdf")
    plt.show()

def plot_flda_vectors(a, b, vectors, w):
    mu_a, mu_b = a.mean(axis=0).reshape(-1,1), b.mean(axis=0).reshape(-1,1)
    mid_point = (mu_a + mu_b)/2

    vector = vectors[:, 0]
    slope_pca = vector[1]/vector[0]
    c_pca = mid_point[1] - slope_pca*mid_point[0]

    slope = w[1]/w[0]
    c = mid_point[1] - slope*mid_point[0]

    x = np.linspace(xmin+1, xmax+1, 100)
    z = np.linspace(xmin+1, xmax+1, 100)

    plt.figure()
    plt.xlim(xmin, xmax)
    plt.ylim(ymin, ymax)
    plt.plot(a[:,0], a[:,1], 'b.', b[:,0], b[:,1], 'r+')
    plt.plot(x, slope*x + c)
    #plt.plot(z, slope_pca*z + c_pca)
    #plt.plot(mu_a, mu_b, 'black')
    plt.legend(['Male', 'Female', 'FisherLDA vector'])
    #plt.legend(['Male', 'Female', 'FisherLDA vector', 'PCA vector', 'Means'])
    pml.savefig("fisher_lda_lines_flda.pdf")
    plt.show()

def plot_pca_vectors(a, b, vectors, w):
    mu_a, mu_b = a.mean(axis=0).reshape(-1,1), b.mean(axis=0).reshape(-1,1)
    mid_point = (mu_a + mu_b)/2

    vector = vectors[:, 0]
    slope_pca = vector[1]/vector[0]
    c_pca = mid_point[1] - slope_pca*mid_point[0]

    slope = w[1]/w[0]
    c = mid_point[1] - slope*mid_point[0]

    x = np.linspace(xmin+1, xmax+1, 100)
    z = np.linspace(xmin+1, xmax+1, 100)

    plt.figure()
    plt.xlim(xmin, xmax)
    plt.ylim(ymin, ymax)
    plt.plot(a[:,0], a[:,1], 'b.', b[:,0], b[:,1], 'r+')
    #plt.plot(x, slope*x + c)
    plt.plot(z, slope_pca*z + c_pca)
    #plt.plot(mu_a, mu_b, 'black')
    plt.legend(['Male', 'Female', 'PCA vector'])
    #plt.legend(['Male', 'Female', 'FisherLDA vector', 'PCA vector', 'Means'])
    pml.savefig("fisher_lda_lines_pca.pdf")
    plt.show()

def plot_proj(name, argument):
    plt.figure()
    if name == 'pca':
        Xproj_pca_male = argument[:nMale]
        Xproj_pca_female = argument[nMale:nFemale]
        plt.hist(Xproj_pca_male, color='red', ec='black')
        plt.hist(Xproj_pca_female, color='blue', ec='black')
        plt.title('Projection of points onto PCA vector')
        pml.savefig("fisher_lda_pca.pdf")
        plt.show()
    else :
        Xproj_fish_male = argument[:nMale]
        Xproj_fish_female = argument[nMale:nFemale]
        plt.hist(Xproj_fish_male, color='red', ec='black')
        plt.hist(Xproj_fish_female, color='blue', ec='black')
        plt.title('Projection of points onto Fisher vector')
        pml.savefig("fisher_lda_flda.pdf")
        plt.show()

"""Data"""

plot_data(a, b)

"""FLDA"""

X_tran, X_fit, w_sk = flda_sklearn(X, Y)
w = flda_manual(a, b)

Xproj_fish_sk = Xproj_fish_sk_cal(w_sk)
Xproj_fish_man, Xproj_fish_male, Xproj_fish_female = Xproj_fish_man_cal(X, w)
Xproj_fish_man = Xproj_fish_man.reshape(-1, 1)
assert np.allclose(Xproj_fish_sk, Xproj_fish_man)

plot_proj('flda', Xproj_fish_man) # Or plot_proj('flda', X_tran) as both the methods give similar results

"""PCA"""

X_fit, X_tran = pca_sklearn(X, Y)
vectors = pca_manual(X, Y)

Xproj_pca_sk = Xproj_pca_sk_cal(X_fit)
Xproj_pca_man, Xproj_pca_male, Xproj_pca_female = Xproj_pca_man_cal(X, vectors)
Xproj_pca_man = Xproj_pca_man.reshape(-1, 1)
assert np.allclose(Xproj_pca_sk, Xproj_pca_man)

plot_proj('pca', Xproj_pca_man) # Or plot_proj('pca', X_tran) as both the methods give similar results

"""Plot of vectors"""

plot_all_vectors(a, b, vectors, w)
plot_pca_vectors(a, b, vectors, w)
plot_flda_vectors(a, b, vectors, w)


#!/usr/bin/env python2

# Author: juscodit@gmail.com

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import math
import sys
from math import pow
from math import exp

matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'

delta = 0.025

### ==============================
### Classical Newton for Rosenbrock function
### ==============================

# Rosenbrock function for point @p
def fr(p):
  return 100.0 * pow((p[1] - pow(p[0], 2)), 2) + pow((1.0 - p[0]), 2)

# gradient at point @p
def gr(p):
  x, y = p
  drx = 400.0 * pow(x, 3) - 400.0 * x * y + 2.0 * x - 2.0
  dry = 200.0 * y - 200.0 * pow(x, 2)
  return np.array([drx, dry])

# hessian matrix
def hr(p):
  x, y = p
  m11 = 1200.0 * pow(x, 2) - 400.0 * y + 2.0
  m12 = -400.0 * x
  m21 = -400.0 * x
  m22 = 200.0
  return np.matrix([[m11, m12], [m21, m22]])

# descent direction
def ddr(p):
  hessian = hr(p)
  heinv = np.linalg.inv(hessian)
  return np.squeeze(np.asarray(np.negative(np.dot(heinv, gr(p)))))

# step length at point @p with respect to descent direction @dd
def alpha_r(p, dd):
  a, r, c1 = 1, 0.3, 1e-4

  g = gr(p)
  p1 = p + a * dd
  while fr(p1) > fr(p) + c1 * a * np.dot(g, dd):
    a *= r
    p1 = p + a * dd

  return a

def classical_newton_r(p0):
  result = []
  result.append(p0)
  pk = p0

  i = 0
  while np.linalg.norm(gr(pk)) > 0.001:
    print "step %d [%f, %f]" % (i, pk[0], pk[1])
    i += 1
    dd = ddr(pk)
    a = alpha_r(pk, dd)
    pk = pk + a * dd
    result.append(pk)

  print "step %d [%f, %f]" % (i, pk[0], pk[1])

  return result

### ==============================
### quadratic approximation for Rosenbrock function at some point
### ==============================

x = np.arange(-1.2, 1.0, delta)
y = np.arange(-0.6, 1.2, delta)
X, Y = np.meshgrid(x, y)
Z = 100 * (Y - X * X) * (Y - X * X) + (1 - X) * (1 - X)

p = (-0.5, 0)
gp = gr(p)
hp = hr(p)
Zapp = fr(p) + (gp[0] * (X - p[0]) + gp[1] * (Y - p[1])) + \
       0.5 * (hp[0, 0] * (X - p[0]) * (X - p[0]) +
              hp[0, 1] * (X - p[0]) * (Y - p[1]) +
              hp[1, 0] * (Y - p[1]) * (X - p[0]) +
              hp[1, 1] * (Y - p[1]) * (Y - p[1]))

plt.figure()
plt.contour(X, Y, Z, [15, 9, 6, 4, 2, 1, 0.1])
plt.contour(X, Y, Zapp, [10, 8, 6, 4, 2, 1], colors='green', linewidths=0.7)
plt.plot(*p, marker='o', color='r')

plt.savefig("rosen3.png")

### ==============================
### Rosenbrock function
### ==============================

x = np.arange(-1.2, 1.0, delta)
y = np.arange(-0.6, 1.2, delta)
X, Y = np.meshgrid(x, y)
Z = 100 * (Y - X * X) * (Y - X * X) + (1 - X) * (1 - X)

## for initial point (0.6, 0.6)

plt.figure()
plt.contour(X, Y, Z, [15, 9, 6, 4, 2, 1, 0.1])

res = classical_newton_r((0.6, 0.6))

xp, yp = zip(*res)
plt.plot(xp, yp, '--', lw=3)

for r in res:
  plt.plot(*r, marker='o', color='r')

plt.savefig("rosen1.png")

## for initial point (-1.2, 1)

plt.figure()
plt.contour(X, Y, Z, [15, 9, 6, 4, 2, 1, 0.1])

res = classical_newton_r((-1.2, 1))

xp, yp = zip(*res)
plt.plot(xp, yp, ls='--', lw=3)

for r in res:
  plt.plot(*r, marker='o', color='r')

plt.savefig("rosen2.png")

### ==============================
### Classical Newton for log(exp(x) + exp(-x))
### ==============================

def gl(x):
  return (exp(x) - exp(-x)) / (exp(x) + exp(-x))

def hl(x):
  return 1 - pow(gl(x), 2)

def classical_newton_l(x0, niter):
  result = []
  hessian = []
  xk = x0
  i = 0
  while gl(xk) != 0 and i < niter:
    result.append(xk)
    hessian.append(hl(xk))
    xk = xk - gl(xk) / hl(xk)
    i += 1
  result.append(xk)
  hessian.append(hl(xk))
  return (result, hessian)

plt.figure()

x = np.arange(-2, 6, .01)
y = np.log(np.exp(x) + np.exp(-x))

(res, hessian) = classical_newton_l(1.1, 4)
print res
print hessian

for r in res:
  plt.plot(r, 0, marker='o', color='r')

tag = 'x0'
plt.annotate(tag, xy=(res[0], 0.05), xytext=(0.5, 0.2), arrowprops=dict(arrowstyle="->"))

tag = 'x1'
plt.annotate(tag, xy=(res[1], 0.05), xytext=(res[1], 0.2))

tag = 'x2'
plt.annotate(tag, xy=(res[2], 0.05), xytext=(1.5, 0.2), arrowprops=dict(arrowstyle="->"))

tag = 'x3'
plt.annotate(tag, xy=(res[3], 0.05), xytext=(res[3], 0.2))

tag = 'x4'
plt.annotate(tag, xy=(res[4], 0.05), xytext=(res[4], 0.2))

plt.plot(x, y, linewidth=2)

plt.savefig("log.png")

# plt.show()


'''Quantum Fourier Transform Simulator for Shor's Algorithm'''

import cirq
import numpy as np

# define the initial four qubits
q0 = cirq.GridQubit(0, 0) # |0〉
q1 = cirq.GridQubit(0, 1) # |0〉
q2 = cirq.GridQubit(1, 0) # |0〉
q3 = cirq.GridQubit(1, 1) # |0〉

def main():
    '''Simulates the Four-qubit QFT Circuit'''

    # create and append the quantum circuit
    circuit = cirq.Circuit()
    circuit.append(initialize_QFT(False)) # i.e., QFT
    circuit.append(initialize_QFT(True)) # i.e., QFT†
    print("\n ┼─────────────────────────────────┼\n",
    "│ Four-qubit QFT Circuit (N = 2⁴) │\n",
    "┼─────────────────────────────────┼\n\n")
    print(circuit)

    # simulate the circuit and print the resulting state vector
    result = cirq.Simulator().simulate(circuit)
    print("\n\n⦿  Final State Vector |ψ₄〉:\n\n")
    print(np.around(result.final_state_vector, 7))

def initialize_QFT(inv=False):
    '''Initializes the Four-qubit QFT Circuit'''

    if inv is True:
        sign = -1 # i.e., QFT†
    else:
        sign = 1 # i.e., QFT

    # GATE 1: apply Hadamard to q0
    yield cirq.H(q0)

    # GATE 2: apply controlled R₂ between q0 and q1
    yield cirq.CZPowGate(exponent=sign*0.5)(q0,q1)

    # GATE 3: apply controlled R₃ between q0 and q2
    yield cirq.CZPowGate(exponent=sign*0.25)(q0,q2)

    # GATE 4: apply controlled R₄ between q0 and q3
    yield cirq.CZPowGate(exponent=sign*0.125)(q0,q3)

    # GATE 5: apply Hadamard to q1
    yield cirq.H(q1)

    # GATE 6: apply controlled R₂ between q1 and q2
    yield cirq.CZPowGate(exponent=sign*0.5)(q1,q2)

    # GATE 7: apply controlled R₃ between q1 and q3
    yield cirq.CZPowGate(exponent=sign*0.25)(q1,q3)

    # GATE 8: apply Hadamard to q2
    yield cirq.H(q2)

    # GATE 9: apply controlled R₂ between q2 and q3
    yield cirq.CZPowGate(exponent=sign*0.5)(q2,q3)

    # GATE 10: apply Hadamard to q3
    yield cirq.H(q3)

    # GATE 11: apply swap between q1 and q2
    yield cirq.SWAP(q1,q2)

    # GATE 12: apply final swap between q0 and q3
    yield cirq.SWAP(q0,q3)

if __name__ == '__main__':
    main()


# Law of large numbers
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (20,10)
from distributionLib import Dist
import os
import imageio
np.random.seed(404)

N = 1000

data = np.random.choice([0, 1], size=(N,1), p=[0.49, 0.51])
E_x = np.sum(data)/N

sampleLook = 801
temp = 0
yData = []
xData = []
sample = 100

plt.plot([0,sampleLook],[E_x,E_x],'r--',label='E(x)')
plt.ylim(E_x - E_x/20, E_x +E_x/20)
plt.xlim(0,sampleLook)
plt.title('Law of Large Numbers')
plt.xlabel('Number of samples')
plt.ylabel('Mean of sample Data')
##filenames = []
for ii in range(sampleLook):
    tSample = np.random.randint(0, N,size=(sample,1))
    temp += np.mean(data[tSample])
    if not ii%10:
        if not ii:
            plt.scatter(ii,temp/(ii+1),color='k',label='Sample Data mean')
            plt.legend()
        else:
            plt.scatter(ii,temp/(ii+1),color='k')
##        filename = f'{ii}.png'
##        filenames.append(filename)
        plt.pause(0.00001)
        plt.draw()
##        plt.savefig(filename)

##with imageio.get_writer('mygif.gif', mode='I') as writer:
##    for filename in filenames:
##        image = imageio.imread(filename)
##        writer.append_data(image)
##
### Remove files
##for filename in set(filenames):
##    os.remove(filename)
##


"""
itoProcess.py

Created by Luca Camerani at 31/08/2020, University of Milano-Bicocca.
(l.camerani@campus.unimib.it)
All rights reserved.

This file is part of the EcoFin-Library (https://github.com/LucaCamerani/EcoFin-Library),
and is released under the "BSD Open Source License".
"""

import math

import numpy as np

from EcoFin.math.stochasticProcess.process import Process
from EcoFin.utils.utils import listInterpreter

class ItoProcess():
    def __init__(self, T, dt, t=0, x0=0, n=None):
        self.T = T
        self.t = t
        self.dt = dt
        self.steps = len(self.getTimeVector())
        self.x0 = x0
        self.n = n
        if n is None: self.n = 1

        self.initSBM()

    def getStepsN(self):
        return math.trunc((self.T - self.t) / self.dt) + 1

    def initSBM(self):
        self.SBM = Process(self.T, self.dt, self.t, n=self.n).standardBrownianMotion(lineCorr=False)
        return self.SBM

    def getTimeVector(self):
        return np.arange(self.t, self.T + 1, self.dt)

    def driftBrownianMotion(self, a, b, scalarCorr=True):
        self.initSBM()
        output = []
        for i in range(0, self.n):
            dX = a * self.dt + b * self.SBM.increments[i]
            output.append(self.x0 + np.cumsum(dX))

        if scalarCorr: output = listInterpreter(output)
        return output

    def geometricBrownianMotion(self, mu, sigma, scalarCorr=True):
        self.initSBM()
        output = []
        for i in range(0, self.n):
            x = [self.x0]
            for k in range(1, self.getStepsN()):
                drift = (mu - .5 * sigma ** 2) * (self.getTimeVector() - self.t)[k]
                diffusion = sigma * self.SBM.process[i][k]
                temp = self.x0 * np.exp(drift + diffusion)
                x.append(temp)

            output.append(x)

        if scalarCorr: output = listInterpreter(output)
        return output

    def meanRevertingProcess(self, k, theta, sigma):
        """
        :param k: mean reversion force
        :type k:
        :param theta: long term value
        :type theta:
        :param sigma:
        :type sigma:
        :return:
        :rtype:
        """
        self.initSBM()
        longTerm = theta - self.x0
        sigmaBis = sigma * np.sqrt(2. / k)
        x = np.zeros(self.steps)
        for i in range(self.steps - 1):
            x[i + 1] = x[i] + k * (longTerm - x[i]) * self.dt + \
                       sigmaBis * self.SBM.increments[i]

        return self.x0 + x


"""Python implementation of a knapsack problem algorithm."""

import numpy as np

def knapsack(items, size):
    """Takes a list of items and a knapsack size.
    Each item should have a value and a weight packed in a tuple/list.
    Returns selected items and max accumulated value.

    >>> items = [(3, 4), (2, 3), (4, 2), (4, 3)]  # (value, weight)
    >>> size = 6
    >>> knapsack(items, size)
    (8.0, [(4, 3), (4, 2)])
    """

    memo = np.zeros([size + 1, len(items) + 1])
    for i in range(1, len(items) + 1):
        value_i, weight_i = items[i - 1]
        for x in range(size + 1):
            prev_item_value = memo[x, i-1]

            # If current size is smaller than item weight,
            # we place the value of the previous item for the given size x...
            if x < weight_i:
                memo[x, i] = prev_item_value
                continue

            # ...otherwise, we accumulate the current item value together with
            # a value of the previous item, if it fits the remaining size.
            # If it doesn't, then just the current item value is taken,
            # but only when it's bigger than the previous item value...
            prev_current_value = memo[x-weight_i, i-1] + value_i

            # That's why, we choose a higher value before assigning it to the current item.
            memo[x, i] = max(prev_item_value, prev_current_value)

    # Having evaluated values for all combinations of items and sizes (items * sizes),
    # we are now able to point the highest one, which is indexed by the last item and size.
    max_value = memo[size, len(items)]

    # We can localize selected items by taking advantage from the fact,
    # that every eligible item value has to be bigger than the previous one
    # on the same weight position. In other words, if values of consecutive items
    # are the same, then we know, that such a value belongs to the first item it occurred.
    knapsack_items = []
    item_idx = len(items) + 1
    while size:
        # Get index of max value in a row. If tie, then index of first occurrence is taken.
        item_idx = memo[size, :item_idx].argmax()
        if item_idx == 0:
            break
        item = items[item_idx - 1]
        knapsack_items.append(item)
        size -= item[1]  # Decrease size by a weight of a selected item.

    return max_value, knapsack_items

if __name__ == "__main__":
    import doctest
    doctest.testmod()


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

from sympy import *
x, y, z = symbols('x y z')
init_printing(use_unicode=True)
print(Eq(x, y))

print(solveset(Eq(x**2, 1), x))
print(solveset(Eq(x**2 - 1, 0), x))
print(solveset(x**2 - 1, x))

print(solveset(x**2 - x, x))
print(solveset(x - x, x, domain=S.Reals))
print(solveset(sin(x) - 1, x, domain=S.Reals))
print(solveset(exp(x), x))
# No solution exists
print(solveset(cos(x) - x, x))
# Not able to find solution
print(linsolve([x + y + z - 1, x + y + 2*z - 3 ], (x, y, z)))

print(linsolve(Matrix(([1, 1, 1, 1], [1, 1, 2, 3])), (x, y, z)))
M = Matrix(((1, 1, 1, 1), (1, 1, 2, 3)))
system = A, b = M[:, :-1], M[:, -1]
print(linsolve(system, x, y, z))
a, b, c, d = symbols('a, b, c, d', real=True)
print(nonlinsolve([a**2 + a, a - b], [a, b]))
print(nonlinsolve([x*y - 1, x - 2], x, y))
print(nonlinsolve([x**2 + 1, y**2 + 1], [x, y]))
system = [x**2 - 2*y**2 -2, x*y - 2]
vars = [x, y]
print(nonlinsolve(system, vars))
system = [exp(x) - sin(y), 1/y - 3]
print(nonlinsolve(system, vars))
print(nonlinsolve([x*y, x*y - x], [x, y]))
system = [a**2 + a*c, a - b]
print(nonlinsolve(system, [a, b]))

print(solve([x**2 - y**2/exp(x)], [x, y], dict=True))
print(solve([sin(x + y), cos(x - y)], [x, y]))
print(solveset(x**3 - 6*x**2 + 9*x, x))
print(roots(x**3 - 6*x**2 + 9*x, x))
print(solve(x*exp(x) - 1, x ))
f, g = symbols('f g', cls=Function)
print(f(x).diff(x))
diffeq = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x))
print(diffeq)
print(dsolve(diffeq, f(x)))
print(dsolve(f(x).diff(x)*(1 - sin(f(x))) - 1, f(x)))


# %%
# Bulk Imports and setup
from IPython.display import display, Math, Latex
import matplotlib.pyplot as plt
import numpy as np

import sympy as sm
from sympy.utilities.lambdify import lambdify, implemented_function
x, y, lamda = sm.symbols('x, y, lamda')

def move_sympyplot_to_axes(p, ax):
    backend = p.backend(p)
    backend.ax = ax
    backend._process_series(backend.parent._series, ax, backend.parent)
    backend.ax.spines['right'].set_color('none')
    backend.ax.spines['bottom'].set_position('zero')
    backend.ax.spines['top'].set_color('none')
    plt.close(backend.fig)

# Defining the equations via sympy
dot_x = x-y   # f(x,y)
dot_y = -2*x**2+y  # g(x,y)
display(Math('\dot{x} = '+ sm.latex(dot_x)))
display(Math('\dot{y} = '+ sm.latex(dot_y)))

# %%
## A matrix from dot(X)=AX (if system is linear)
# We contruct the vector <f(x,y), g(x,y)>.
A_vector = sm.Matrix([dot_x, dot_y])
# Jacobian for the A_vector. In a linear system this gives the A matrix from dot(X)=AX
A_matrix = A_vector.jacobian(([x, y]))
display(Math('\mathbf{A} = '+ sm.latex(A_matrix)))
# %%
# Calculates Characteristic Polynomial
charpoly = A_matrix.charpoly()
charpoly
# %%
# Setting equations to zero and computing Fixed Points
dot_x_Equal, dot_y_Equal = sm.Eq(dot_x, 0), sm.Eq(dot_y, 0)
equilibria = sm.solve((dot_x_Equal, dot_y_Equal), x, y, dict=True)
# %%
# Calculates eigenvals and eigenvects for each eq
# The list is of the form [{eq}, [eigenthing1, eigenthing1]]
# Each eigenthing is [(eigenval, multiplicity, [eigenvec]), …]
eigen_things = [[eq, A_matrix.subs(eq).eigenvects()]
              for eq in equilibria]
# Showing equilibrium and eigenthings

for eq in equilibria:
    display(Math("\mathrm{Equilibrium}: (" + sm.latex(eq[x])+","+sm.latex(eq[y])+")"))
    # eigen_things[#eq][eigenthings][#pair][0=value, 1=mult, 2=eigenvect]
    for pair in eigen_things[0][1]:
            display(Math("\mathrm{Eigenvalue}:"+ sm.latex(pair[0]) +
                         "\quad \mathrm{Multiplicity}=" + sm.latex(pair[1])))
            display(Math("\mathrm{Eigenvector}: "+ sm.latex(pair[2][0])))
# %%
# Ploting  parameters
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(1,1,1)
# ax.set_title("Sistema diferencial")

# Setting Plot Boundaries (needed of sympy)
x_min, y_min, y_max, x_max = -2, -2, 2, 2
# For plotting the trajectory
time, dt = 50, 0.1
x_0, y_0 = 0.5, 0.6

# Choose if normalization of vectors is applied
normalize = True

#################################
# Plot fixed points
for point in equilibria:
    ax.plot(point[x],point[y],"red", marker = "o", markersize = 10.0)

# To plot we translate from sympy to numpy
x_movement = lambdify((x, y), dot_x)
y_movement = lambdify((x, y), dot_y)

# define a grid and compute direction at each point
x_line = np.linspace(x_min, x_max, 20)
y_line = np.linspace(y_min, y_max, 20)

# Plot a singular trayectory
x_list= [x_0]
y_list = [y_0]
for i in range(time):
    x_list.append(x_list[i] + (x_movement(x_list[i], y_list[i])) * dt)
    y_list.append(y_list[i] + (y_movement(x_list[i], y_list[i])) * dt)

ax.plot(x_list, y_list, color="black")

# Quiverplot
# create a grid and set the dir vecs
X, Y = np.meshgrid(x_line, y_line)
x_dir, y_dir = x_movement(X,Y), y_movement(X,Y)
# prepare the colour and normalization factor
norm = np.sqrt(x_dir**2 + y_dir**2)

#Normalize
if normalize:
    x_dir /= norm
    y_dir /= norm

plt.quiver(X, Y,
           x_dir,
           y_dir,
           norm,
           pivot='mid')

# Plot Nullclines
p1 = sm.plot_implicit(dot_x_Equal, (x, x_min, x_max), (y, y_min, y_max), show= False)
p2 = sm.plot_implicit(dot_y_Equal, (x, x_min, x_max), (y, y_min, y_max), show= False)

move_sympyplot_to_axes(p1, ax)
move_sympyplot_to_axes(p2, ax)

plt.show()


import numpy as np
import matplotlib.pyplot as plt

# we set alpha, which is the discount rate as 0.5
alpha = 0.5

dict_action = {
    1: 'left',
    2: 'hold_still',
    3: 'right'
}

# reward defination

def left(s):
    if s == -10:
        s = -10
        reward = -11
    elif s == 1:
        s = 0
        reward = 99
    else:
        s = s - 1
        reward = -1
    return s, reward

def right(s):
    if s == 10:
        s = 10
        reward = -11
    elif s == -1:
        s = 0
        reward = 99
    else:
        s = s + 1
        reward = -1
    return s, reward

def hold_still(s):
    if s == 0:
        return s, 99
    else:
        return s, -1

def get_q_array(v): # after solving the Bellman equation, we get v(s) = reward + alpha * v(s')
    q_array = np.zeros([21, 3]) # -10 to 10
    coords = [k for k in range(-10, 11)]
    for i in range(21):
        for j in range(3): # j = 0, 1, 2 to match the dictionary, we have num = j + 1
            s = coords[i]
            num = j + 1
            if num == 1: # left
                s_prime, reward = left(s)
            elif num ==2: # hold_still
                s_prime, reward = hold_still(s)
            else: # right
                s_prime, reward = right(s)
            q_array[i, j] = reward + alpha * v[coords.index(s_prime)]
    return q_array

def get_policy(q_array):
    return np.argmax(q_array, axis=1) + 1 # 1: left, 2: hold_still, 3: right, find the max value in each row
def update_v(pi, q_array):
    v = np.zeros([21, 1])
    for i in range(21):
        v[i] = q_array[i, pi[i]-1]
    return v

def solve_for_v(pi):
    '''
    For this problem, the equation can be represented as the following format:
    v_pi_k = r_pi_k + alpha * P_pi_k * v_pi_k
    in matrix form
    R = (I - alpha*A)V
    V = (I - alpha*A)^(-1) * R

    A ∈ R^(21 * 21)
    alpha = 0.5
    I is a unit matrix
    '''
    # the equation for this problem is v_pi_k = r_pi_k + alpha * P_pi_k * v_pi_k
    # initialization
    A = np.zeros([21, 21])
    V = np.zeros([21, 1])
    R = np.zeros([21, 1])
    I = np.mat(np.identity(21))

    coords = [k for k in range(-10, 11)]

    for i in range(21):
        s = coords[i]
        action = pi[i]
        if action == 1: # left
            s_prime, reward = left(s)
        elif action == 2: # hold_still
            s_prime, reward = hold_still(s)
        else: # right
            s_prime, reward = right(s)
        R[i] = reward
        A[i, coords.index(s_prime)] = 1

    V = np.dot(np.linalg.inv(I - alpha * A), R)  # use broadcast mechanism
    return V

def main():
    # initialize
    q_array = np.zeros([21, 3])
    pi = np.ones([21, 1]) # initial policy

    diff_norm = np.float(100) # a very large number comparing to eps
    eps = np.float(10**-6)
    count = 0
    print('policy-based method bgeins!')

    while(diff_norm >= eps):
        v_pre = solve_for_v(pi)
        q_array = get_q_array(v_pre)
        pi = get_policy(q_array) # pi is policy, here it is updated. Actually this function can be merged to get_q_array, we divided it into two parts for readability
        v = solve_for_v(pi)
        diff_norm = np.linalg.norm(v - v_pre) # we use Euclidean distance as the loss evaluator
        count = count + 1

    print('done!')
    print('action value matrix: ')
    print(q_array)
    print('state values:')
    print(v)
    print('the optimal policy is: ')
    print(pi)
    print('time of iterations:', count, ' alpha =', alpha)

    fig = plt.figure()
    x = [k for k in range(-10, 11)]
    plt.scatter(x, pi)
    plt.title('policy_based_method')
    plt.ylabel('action')
    plt.xlabel('s')
    plt.show()

if __name__ == '__main__':
    main()


try:
    import numpy as _np
    from math import sqrt as _sqrt, log as _log
    from typing import Union, Tuple, Dict, List
    from univariate._base import BoundedInterval
except Exception as e:
    print(f"some modules are missing {e}")

class Uniform(BoundedInterval):
    """
    This class contains methods concerning the Continuous Uniform Distribution [#]_.

    .. math::
        \\text{Uniform}(x;a,b) = \\frac{1}{b-a}

    Args:

        a(float): lower limit of the distribution
        b(float): upper limit of the distribution where b > a

    Referene:
        .. [#] Weisstein, Eric W. "Uniform Distribution." From MathWorld--A Wolfram Web Resource. https://mathworld.wolfram.com/UniformDistribution.html
    """

    def __init__(self, a: float, b: float) -> None:
        self.a = a
        self.b = b

    def pdf(self, x: Union[List[float], _np.ndarray, float]) -> Union[float, _np.ndarray]:
        """
        Args:
            x (Union[List[float], numpy.ndarray, float]): random variable(s)

        Returns:
            Union[float, numpy.ndarray]: evauation of pdf at x
        """
        a = self.a
        b = self.b

        if isinstance(x, (_np.ndarray, List)):
            x0 = 1/(b-a)
            if not type(x) is _np.ndarray:
                x = _np.array(x)
            return _np.piecewise(x, [(a <= x) & (x <= b), (a > x) | (x > b)], [x0, 0.0])

        return 1 / (b - a) if a <= x and x <= b else 0.0

    def cdf(self, x: Union[List[float], _np.ndarray, float]) -> Union[float, _np.ndarray]:
        """
        Args:
            x (Union[List[float], numpy.ndarray, float]): data point(s) of interest

        Returns:
            Union[float, numpy.ndarray]: evaluation of cdf at x
        """
        a = self.a
        b = self.b

        def __generator(a: float, b: float, x: float) -> float:
            if x < a:
                return 0.0
            if a <= x and x <= b:
                return (x - a) / (b - a)
            if x > b:
                return 1.0

        if isinstance(x, (_np.ndarray, List)):
            if not type(x) is _np.ndarray:
                x = _np.array(x)
            # performance could be improved with np.piecewise
            return _np.vectorize(__generator)(a, b, x)

        return __generator(a, b, x)

    def mean(self) -> float:
        """
        Returns: Mean of the Uniform distribution.
        """
        return 1 / 2 * (self.a + self.b)

    def median(self) -> float:
        """
        Returns: Median of the Uniform distribution.
        """
        return 1 / 2 * (self.a + self.b)

    def mode(self) -> Tuple[int, int]:
        """
        Returns: Mode of the Uniform distribution.

        Note that the mode is any value in (a,b)
        """
        return (self.a, self.b)

    def var(self) -> float:
        """
        Returns: Variance of the Uniform distribution.
        """
        return 1 / 12 * pow(self.b - self.a, 2)

    def std(self) -> float:
        """
        Returns: Standard deviation of the Uniform distribution.
        """
        return _sqrt(1 / 12 * pow(self.b - self.a, 2))

    def skewness(self) -> float:
        """
        Returns: Skewness of the Uniform distribution.
        """
        return 0.0

    def kurtosis(self) -> float:
        """
        Returns: Kurtosis of the Uniform distribution.
        """
        return -6 / 5

    def entropy(self) -> float:
        """
        Returns: entropy of uniform Distirbution.

        Reference: Park, S.Y. & Bera, A.K.(2009). Maximum entropy autoregressive conditional heteroskedasticity model. Elsivier.
        link: http://wise.xmu.edu.cn/uploadfiles/paper-masterdownload/2009519932327055475115776.pdf
        """
        return _log(self.b-self.a)

    def summary(self) -> Dict[str, Union[float, Tuple[int, int]]]:
        """
        Returns:
            Dictionary of Uniform distirbution moments. This includes standard deviation.
        """
        return {
            'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
            'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
        }


import numpy as np

class AutoDiff():
    '''
    Class to use for automatic differentiation, forward mode

    Addresses the following need.

    1) The user has some function which maps some number of input variables, for example x and y, to a single
    output value, f(x,y).

    2) The user would like to calculate f(x,y) at a point (x,y) that they specify, as well as the partial
    derivatives df/dx and df/dy at that same point (x, y).

    By first defining their input variables as AutoDiff objects, and then using these objects in
    standard python calculations, including with numpy functions, the user is returned a AutoDiff object
    whose val attribute is the value of the function, and whose derv attribute is the derivative of the function.

    Which partial derivative is stored in the derv attribute of the final AutoDiff object depends on which
    input variable's derv attribute is initially set to 1, while the derv attributes of the other input variables
    are set to 0.

    Example:
    x = AutoDiff(3,1)
    y = AutoDiff(2,0)
    f = x**2 + y**2 + 4
    print(f.val, f.dev)
    (17, 6)
    '''

    def __init__(self, val, derv=1):
        self.val = float(val)
        self.derv = float(derv)

    # -----------Overloading Urnary functions ---------------------------------------------

    def __pos__(self):
        return AutoDiff(self.val, self.derv)

    def __neg__(self):
        return AutoDiff(-1*self.val, -1*self.derv)

    # -----------Add, Subtract, Multiple, Divide functions --------------------------------

    def __mul__(self, other):
        try:
            return AutoDiff(self.val * other.val, self.derv * other.val + other.derv*self.val)
        except:
            return AutoDiff(self.val * other, self.derv * other)

    def __rmul__(self, other):
        return AutoDiff(self.val * other, self.derv * other)

    def __truediv__(self, other):
        try:
            return AutoDiff(self.val/other.val, self.derv/other.val + ( -1*self.val/(other.val**2) ) *other.derv)
        except:
            return AutoDiff(self.val/other, self.derv/other)

    def __rtruediv__(self, other):
        return AutoDiff(other/self.val,  -1*other/(self.val**2) )

    def __add__(self, other):
        try:
            return AutoDiff(self.val + other.val, self.derv + other.derv)
        except:
            return AutoDiff(self.val + other, self.derv + 0)

    def __radd__(self, other):
        return AutoDiff(self.val + other, self.derv + 0)

    def __sub__(self, other):
        try:
            return AutoDiff(self.val - other.val, self.derv + -1*other.derv)
        except:
            return AutoDiff(self.val - other, self.derv + 0)

    def __rsub__(self, other):
        return AutoDiff(other - self.val, -1*self.derv + 0)

    # -----------Overloading Trigonometric functions ---------------------------------------------

    def sin(self):
        return AutoDiff(np.sin(self.val), np.cos(self.val)*self.derv)

    def cos(self):
        return AutoDiff(np.cos(self.val), -1*np.sin(self.val)*self.derv)

    def tan(self):
        return AutoDiff(np.tan(self.val), (1/(np.cos(self.val)**2))*self.derv)

    def arcsin(self):
        if (self.val < -1) or (self.val > 1):
            raise ValueError(' Input to arcsin() must be between -1 and 1 inclusive.')
        else:
            return AutoDiff(np.arcsin(self.val), 1/np.sqrt(1 - (self.val)**2)*self.derv)

    def arccos(self):
        if (self.val < -1) or (self.val > 1):
            raise ValueError(' Input to arccos() must be between -1 and 1 inclusive.')
        else:
            return AutoDiff(np.arccos(self.val), -1/np.sqrt(1 - (self.val)**2)*self.derv)

    def arctan(self):
        return AutoDiff(np.arctan(self.val), 1/(1 + (self.val)**2)*self.derv)

    # -----------Overloading Hyperbolic functions ---------------------------------------------

    def sinh(self):
        return AutoDiff(np.sinh(self.val), np.cosh(self.val)*self.derv)

    def cosh(self):
        return AutoDiff(np.cosh(self.val), np.sinh(self.val)*self.derv)

    def tanh(self):
        return AutoDiff(np.tanh(self.val), (1/np.cosh(self.val))**2*self.derv)

    def arcsinh(self):
        return AutoDiff(np.arcsinh(self.val), 1/np.sqrt(1 +(self.val)**2)*self.derv)

    def arccosh(self):
        return AutoDiff(np.arccosh(self.val), 1/np.sqrt((self.val)**2 - 1) *self.derv)

    def arctanh(self):
        return AutoDiff(np.arctanh(self.val), 1/(1 - (self.val)**2) *self.derv)

    # -----------Overloading Power functions ---------------------------------------------

    def __pow__(self, other):
        try:
            return AutoDiff(self.val**other.val, other.val*self.val**(other.val - 1)*self.derv  +  self.val**other.val*np.log(self.val)*other.derv )
        except:
            return AutoDiff(self.val**other, other*self.val**(other - 1)*self.derv)

    def __rpow__(self, other):
        return AutoDiff(other**self.val, other**self.val*np.log(other)*self.derv)

    def exp(self):
        return AutoDiff(np.exp(self.val), np.exp(self.val)*self.derv)

    # -----------Overloading log functions ---------------------------------------------

    def log(self):
        return AutoDiff(np.log(self.val), (1/self.val)*self.derv)

    def log10(self):
        return AutoDiff(np.log10(self.val), (1/(np.log(10)*self.val))*self.derv)

    def log2(self):
        return AutoDiff(np.log2(self.val), (1 / (np.log(2) * self.val)) * self.derv)

    # -----------Overloading the Square Root function ------------------------------------------

    def sqrt(self):
        return AutoDiff(np.sqrt(self.val), (1/(2*np.sqrt(self.val) )*self.derv) )

    # -----------Overloading the logistic function ---------------------------------------------

    def logist(self):
        return AutoDiff( 1/(1 + np.exp(-1*(self.val))), (1/(1 + np.exp(-1*(self.val)))) * (1 - (1/(1 + np.exp(-1*(self.val))))) *self.derv)

    #-----------Overloading the Comparison Operators >, <, >=, <=, ==. != -------------------------

    def __lt__(self, other):
        try:
            if self.val < other.val:
                return True
            else:
                return False
        except:
            if self.val < other:
                return True
            else:
                return False

    def __gt__(self, other):
        try:
            if self.val > other.val:
                return True
            else:
                return False
        except:
            if self.val > other:
                return True
            else:
                return False

    def __le__(self, other):
        try:
            if self.val <= other.val:
                return True
            else:
                return False
        except:
            if self.val <= other:
                return True
            else:
                return False

    def __ge__(self, other):
        try:
            if self.val >= other.val:
                return True
            else:
                return False
        except:
            if self.val >= other:
                return True
            else:
                return False

    def __eq__(self, other):
        try:
            if self.val == other.val:
                return True
            else:
                return False
        except:
            if self.val == other:
                return True
            else:
                return False

    def __ne__(self, other):
        try:
            if self.val != other.val:
                return True
            else:
                return False
        except:
            if self.val != other:
                return True
            else:
                return False


# -*- coding: utf-8 -*-
"""
Created on Sun Dec  3 11:43:10 2017

@author: chris
"""

import numpy as np

def f(x,mu,sigma):
    return 1/(np.sqrt(2*np.pi)*sigma) * np.exp(-(x - mu)**2 / (2*sigma**2))

def mixture(x,p,mu,sigma):
    result = p[0]*f(x,mu[0],sigma[0]) # compatible with vector and scalar
    for h in range(1,len(p)):
        result += p[h]*f(x,mu[h],sigma[h])
    return result

def EM(y,p,mu,sigma):
    n = len(y)
    c = len(p)
    w = np.zeros([c,n])
    re_p = np.zeros(c)
    re_mu = np.zeros(c)
    re_sigma = np.zeros(c)
    re_logL = 0
    # E-step
    for j in range(n):
        tmp = mixture(y[j],p,mu,sigma)
        for i in range(c):
            w[i,j] = p[i] * f(y[j],mu[i],sigma[i]) / tmp
            re_logL += w[i,j] * (np.log(p[i]*f(y[j],mu[i],sigma[i])))
            # w[i,j] = p[i] * f(y[j],mu[i],sigma[i]) / mixture(y[j],p,mu,sigma)
            # use tmp to reduce computational complexity
    # M-step
    for i in range(c):
        re_p[i] = np.mean(w[i])
        re_mu[i] = sum(w[i]*y) / sum(w[i])
        re_sigma[i] = np.sqrt(sum(w[i] * (y-re_mu[i])**2) / sum(w[i]))
    return re_p,re_mu,re_sigma,re_logL

## simulation
np.random.seed(0)
N = 400
#Y = np.append(np.append( np.random.normal(loc=-2,scale=1,size=N//4) , np.random.normal(loc=2,scale=1,size=N//2)) , np.random.normal(loc=6,scale=1,size=N//4))
Y = np.append( np.random.beta(4,1,size=N//2) , np.random.beta(1,4,size=N//2))

## hyper-parameter
g = 5

## EM control parameter
cache_size = 1000
tol = 1e-4

## init
em_p = np.zeros([cache_size,g])
em_mu = np.zeros([cache_size,g])
em_sigma = np.zeros([cache_size,g])
em_l = np.zeros([cache_size])
em_la = np.zeros([cache_size])

em_p[0] = np.ones(g)/g
em_mu[0] = np.random.normal(loc=np.mean(Y),scale=np.std(Y),size=g)
em_sigma[0] = np.ones(g) * np.std(Y)
em_p[0],em_mu[0],em_sigma[0],em_l[0] = EM(Y,em_p[0],em_mu[0],em_sigma[0]) ## calculate logL via EM

t=0
while (t+1 < cache_size):
    em_p[t+1],em_mu[t+1],em_sigma[t+1],em_l[t+1] = EM(Y,em_p[t],em_mu[t],em_sigma[t])
    if (t>0):
        a = (em_l[t+1] - em_l[t]) / (em_l[t] - em_l[t-1])
        em_la[t+1] = em_l[t] + (em_l[t+1]-em_l[t])/(1-a)
        if (abs(em_la[t+1] - em_la[t]) < tol or np.isnan(em_la[t+1])):
            break;
    t += 1

from matplotlib import pyplot as plt
from scipy import stats

# example 1
n,bins,patches = plt.hist(Y,bins=30,normed=1,color=[0.4,0.8,0.8])
plt.plot(bins,mixture(bins,em_p[t-1],em_mu[t-1],em_sigma[t-1]),ls='--',color=[0.4,0.2,0.9])
plt.plot(bins,mixture(bins,[0.25,0.5,0.25],[-2,2,6],[1,1,1]),ls='--',color=[0.8,0.3,0.2])
plt.legend(('mixture model','real distribution'))
plt.title("g=%d , convergence after %d iterations"%(g,t))
plt.savefig(filename='E://workspace//ex1g%d.png'%g,dpi=100)

# example 2
n,bins,patches = plt.hist(Y,bins=30,normed=1,color=[0.4,0.8,0.8])
plt.plot(bins,mixture(bins,em_p[t-1],em_mu[t-1],em_sigma[t-1]),ls='--',color=[0.4,0.2,0.9])
plt.plot(bins,0.5*stats.beta.pdf(bins, 1, 4) + 0.5*stats.beta.pdf(bins, 4, 1), 'r-')
#plt.plot(bins,0.5*stats.beta.pdf(bins, 4, 1), 'g-')
plt.legend(('mixture model','real distribution'))
plt.title("g=%d , convergence after %d iterations"%(g,t))
plt.savefig(filename='E://workspace//ex2g%d.png'%g,dpi=100)


# -*- coding: utf-8 -*-
"""
Created on Wed Feb 27 08:55:58 2019

@author: Ham

HackerRanch Challenge: Linear Algebra

The NumPy module also comes with a number of built-in routines
for linear algebra calculations.
These can be found in the sub-module linalg.

linalg.det

The linalg.det tool computes the determinant of an array.

print numpy.linalg.det([[1 , 2], [2, 1]])       #Output : -3.0

linalg.eig

The linalg.eig computes the eigenvalues and right eigenvectors of a square array.

vals, vecs = numpy.linalg.eig([[1 , 2], [2, 1]])
print vals                  #Output : [ 3. -1.]
print vecs                  #Output : [[ 0.70710678 -0.70710678]
                            #          [ 0.70710678  0.70710678]]

linalg.inv

The linalg.inv tool computes the (multiplicative) inverse of a matrix.

print numpy.linalg.inv([[1 , 2], [2, 1]])   #Output : [[-0.33333333  0.66666667]
                                            #          [ 0.66666667 -0.33333333]]

Other routines can be found here

Task

You are given a square matrix A with dimensions NxN.
Your task is to find the determinant.

Input Format

The first line contains the integer N.
The next N lines contains the N space separated elements of array A.

Output Format

Print the determinant of A.

Sample Input

2
1.1 1.1
1.1 1.1

Sample Output

0.0

"""

import io
import numpy

STDIN_SIO = io.StringIO("""
3
1 2 3
4 5 6
1 2 1
""".strip())

if __name__ == '__main__':
    #a = [list(map(float, input().split())) for _ in range(int(input()))]
    a = [list(map(float, STDIN_SIO.readline().strip().split()))
         for _ in range(int(STDIN_SIO.readline()))]
    print(a)
    print(round(numpy.linalg.det(a), 2))


## =========================================================================
## @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
## =========================================================================

import numpy, sys
import matplotlib.pyplot as plotter
from matplotlib import cm

# Check input arguments
if len( sys.argv ) < 2:
  print( "Usage:", sys.argv[ 0 ], "input.csv" )
  sys.exit( 1 )
# end if

# Load data
print( "reading" )
X = numpy.genfromtxt( sys.argv[ 1 ], delimiter = ',' )
print( "done: ", X.shape )

# PCA
m = X.mean( axis = 0 )
c = X - m
S = ( c.T @ c ) / float( X.shape[ 0 ] )
[ v, R ] = numpy.linalg.eig( S )
idx = v.argsort( )[ : : -1 ]
v = v[ idx ]
R = R[ : , idx ]
retention = v / v.sum( )

# Projection onto PCA
pX = ( ( X - m ) @ R )[ : , : 1 ]

# ---> Usar pX como los datos de entrada para la RN, SVM, Arbol, Bagg...

pX = numpy.append( pX, numpy.zeros( ( pX.shape[ 0 ], 1 ) ), axis = 1 )

# Backprojection from PCA
rX = ( pX @ R.T ) + m

print( "mean:\n", m )
print( "covariance:\n", S )
print( "values:\n", v )
print( "vectors:\n", R )
print( "retention:\n", retention )
print( "inverse:\n", numpy.linalg.inv( R ) )
print( "transpose:\n", R.T )
print( "inverse - transpose:\n", numpy.linalg.inv( R ) - R.T )
print( "norm e0:\n", numpy.linalg.norm( R, axis = 0 ) )
print( "norm e1:\n", numpy.linalg.norm( R, axis = 1 ) )
print( "Frobenius norm:\n", numpy.linalg.norm( R ) )

# Show initial configuration
fig, ax1 = plotter.subplots( )
ax1.axis( 'equal' )
data_X, data_Y = zip( *X )
data_pX, data_pY = zip( *pX )
data_rX, data_rY = zip( *rX )
plotter.scatter(
    data_X, data_Y, c = "#ff0000", marker = "x"
    )
plotter.scatter(
    data_pX, data_pY, c = "#00ff00", marker = "o"
    )
plotter.scatter(
    data_rX, data_rY, c = "#0000ff", marker = "+"
    )
plotter.quiver(
    [ m[ 0 ], m[ 0 ] ], [ m[ 1 ], m[ 1 ] ],
    [ R[ 0 ][ 0 ], R[ 0 ][ 1 ] ],
    [ R[ 1 ][ 0 ], R[ 1 ][ 1 ] ]
    )
plotter.show( )

# eof - $RCSfile$


#!/opt/local/bin/python3
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Cody R. Drisko. All rights reserved.
# Licensed under the MIT License. See the LICENSE file in the project root for more information.
#
# Name: validate.py - Version 1.0.0
# Author: crdrisko
# Date: 10/29/2020-09:20:01
# Description: Validate the results of the finiteDifferencesExample using numpy's gradient and scipy's cumtrapz

import numpy as np
from scipy import integrate

x = np.linspace(0, 10000.1, 100002)
y = (4 * x**2) + (2 * x) - 7

derivative1st = np.gradient(y, x)
integral2nd = integrate.cumtrapz(derivative1st, x, initial=0.0)

integral1st = integrate.cumtrapz(y, x, initial=0.0)
derivative2nd = np.gradient(integral1st, x)

counter1 = 0
counter2 = 0

tolerance = 2 * (x[1] - x[0])

for i in range(1, np.size(x) - 1):
    if y[i] - (integral2nd[i] - 7) <= tolerance:
        counter1 += 1

    if y[i] - derivative2nd[i] - 2 <= tolerance:
        counter2 += 1

print("The calculation of ∫(dy / dx) dx resulted in %d out of %d elements within %0.1f of the exact result."
    % (counter1, np.size(y) - 2, tolerance))

print("The calculation of d(∫y dx) / dx resulted in %d out of %d elements within %0.1f of the exact result."
    % (counter2, np.size(y) - 2, tolerance))


import numpy as np
from caid.cad_geometry import cad_nurbs
from matplotlib import pyplot as plt
from numpy import pi, array

# ... create a 3D curve
def make_curve():
    T = np.array([0., 0., 0., 0.5, 0.75, 0.75, 1., 1., 1.])
    C = [[ 6.0, 0.0, 6.0],
         [-5.5, 0.2, 5.5],
         [-5.0, 1.3,-5.0],
         [ 4.5, 2.,-4.5],
         [ 4.0, 2.5, 4.0],
         [-3.5, 2.75, 3.5],]

    crv = cad_nurbs([T], C)
    return crv
# ...

# ... custom plot curve
def curve_plot(crv, text="P", color="r" \
               , xmin=None, xmax=None \
               , ymin=None, ymax=None \
               , n_points=100):

    frame1 = plt.gca()
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)
    frame1.set_frame_on(False)

    if (xmin is not None) and (xmax is not None):
        plt.xlim(xmin, xmax)

    if (ymin is not None) and (ymax is not None):
        plt.ylim(ymin, ymax)

    t = np.linspace(0.0,1.0,n_points)
    C = crv.points
    P = crv(t)
    x = P[:,0]
    y = P[:,1]

    plt.plot(x,y, color)

    i = 0
    for [xc,yc,zc] in C:
        label = "$"+text+"_{%s}$" % (str(i+1))
        plt.text(xc-0.05,yc+0.05, label, fontsize=14, color="k")
        plt.plot(xc,yc, "ok")
        i += 1
    # control polygon
    plt.plot(C[...,0], C[...,1], "-.k")
# ...

# ... create a 3D curve
crv0 = make_curve()
crv1 = make_curve()
# ...

# ... refine the curve by inserting the knot 0.5
crv1.refine(0, [0.5])
# ...

# ... raising the spline degree
crv1.elevate(0,1)
# ...

# ... define the matplotlib grid
xmin = -6.5 ; xmax = 7.
ymin = -0.5 ; ymax = 3.25
# ...

curve_plot(crv0, text="P", color="b")
plt.savefig("curve_ex1_original.png")
plt.clf()

curve_plot(crv1, text="Q", color="r")
plt.savefig("curve_ex1_refined.png")
plt.clf()