# coding: utf-8

# ### DEMAPP01
# # Approximating functions on R

# This demo illustrates how to use CompEcon Toolbox routines to construct and operate with an approximant for a function defined on an interval of the real line.
#
# In particular, we construct an approximant for $f(x)=\exp(-x)$ on the interval $[-1,1]$.  The function used in this illustration posseses a closed-form, which will allow us to measure approximation error precisely. Of course, in practical applications, the function to be approximated will not possess a known closed-form.
#
# In order to carry out the exercise, one must first code the function to be approximated at arbitrary points.
# Let's begin:

# In[1]:

import numpy as np
import matplotlib.pyplot as plt
from compecon import BasisChebyshev, BasisSpline, demo

# ### Preliminary tasks

# Function to be approximated and derivatives

# In[2]:

def f(x): return np.exp(-x)
def d1(x): return -np.exp(-x)
def d2(x): return np.exp(-x)

# Set degree and domain of interpolation

# In[3]:

n, a, b = 10, -1, 1

# This function will be used to plot the $y=0$ line in all figures.

# In[4]:

def plotzero():
    plt.hlines(0,a,b, 'k', linestyle='--',linewidth=2)

# ### Choose an approximation scheme.

# #### Chebyshev interpolation

# In this case, let us use an order 10 Chebychev approximation scheme:

# In[5]:

F = BasisChebyshev(n, a, b, f=f)

# One may now evaluate the approximant at any point x calling the basis:

# In[6]:

x = 0
ffit = F(x)

# ... one may also evaluate the approximant's first and second derivatives at x:

# In[7]:

dfit1 = F(x, 1)
dfit2 = F(x, 2)

# ... and one may even evaluate the approximant's definite integral between the left endpoint a and x:

# In[8]:

intfit = F(x, -1)

# ###  Compare analytic and numerical computations

# In[9]:

print('Function Values, Derivatives and Definite Integral of exp(-x) at x=0')
print('%-20s %12s %12s' % (' ', 'Numerical', 'Analytic'))
print('%-20s %12.8f %12.8f' % ('Function', ffit, f(x)))
print('%-20s %12.8f %12.8f' % ('First Derivative', dfit1,  d1(x)))
print('%-20s %12.8f %12.8f' % ('Second Derivative', dfit2,  d2(x)))
print('%-20s %12.8f %12.8f' % ('Definite Integral', intfit,  np.exp(1)-1))

# ### Plots of approximation errors

# One may evaluate the accuracy of the Chebychev polynomial approximant by computing the approximation error on a highly refined grid of points:

# In[10]:

nplot = 501  # number of grid nodes
xgrid = np.linspace(a, b, nplot)    # generate refined grid for plotting

figures=[]

def approx_error(true_func, appr_func, d=0, title=''):
    demo.figure(title, 'x', 'Error')
    plotzero()
    plt.plot(xgrid, appr_func(xgrid, d) - true_func(xgrid))
    plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
    figures.append(plt.gcf())

# #### Plot function approximation error

# In[11]:

approx_error(f,F,title='Chebychev Approximation Error - Function')

# The plot indicates that an order 10 Chebychev approximation scheme, produces approximation errors no bigger in magnitude than $6\times10^{-10}$. The approximation error exhibits the "Chebychev equioscillation property", oscilating relatively uniformly throughout the approximation domain.
#
# This commonly occurs when function being approximated is very smooth, as is the case here but should not be expected when the function is not smooth.  Further notice how the approximation error is exactly 0 at the approximation nodes --- which is true by contruction.

# #### Plot first derivative approximation error

# In[12]:

approx_error(d1,F,1, title='Chebychev Approximation Error - First Derivative')

# #### Plot second derivative approximation error

# In[13]:

approx_error(d2,F,2, title='Chebychev Approximation Error - Second Derivative')

# ### Cubic spline interpolation

# Let us repeat the approximation exercise, this time constructing a 21-function cubic spline approximant:

# In[14]:

n = 21                         # order of approximation
S = BasisSpline(n, a, b, f=f)  # define basis
yapp = S(xgrid)                # approximant values at grid nodes

# #### Plot function approximation error

# In[15]:

approx_error(f,S,title='Cubic Spline Approximation Error - Function')

# The plot indicates that an order 21 cubic spline approximation scheme produces approximation errors no bigger in magnitude than $1.2\times10^{-6}$, about four orders of magnitude worse than with Chebychev polynomials.

# #### Plot first derivative approximation error

# In[16]:

approx_error(d1,S,1, title='Cubic Spline Approximation Error - First Derivative')

# #### Plot second derivative approximation error

# In[17]:

approx_error(d2,S,2, title='Cubic Spline Approximation Error - Second Derivative')

# ### Linear spline interpolation

# Let us repeat the approximation exercise, this time constructing a 31-function linear spline approximant:

# In[18]:

n = 31
L = BasisSpline(n, a, b, k=1, f=f)

# #### Plot function approximation error

# In[19]:

approx_error(f,L,title='Linear Spline Approximation Error - Function')

# The plot indicates that an order 21 cubic spline approximation scheme produces approximation errors no bigger in magnitude than $1.2\times10^{-6}$, about four orders of magnitude worse than with Chebychev polynomials.

# In[20]:

demo.savefig(figures)


# -*- coding: utf-8 -*-
#-----------------------------------------------------------------------------------------
# Name:          geometry.py
# Purpose:       Geometry related Utilities
#
# Author:        Indranil Sinharoy
#
# Created:       06/30/2015
# Last Modified: 04/08/2017
# Copyright:     (c) Indranil Sinharoy 2015 - 2017
# License:       MIT License
#-----------------------------------------------------------------------------------------
"""Utility functions for geometry. All examples in docstrings assume that the module has
   been imported as ``geo``
"""

from __future__ import division, print_function
import numpy as _np

class Point(object):
    """Point class represent a point in 3d space"""

    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return '{0.__name__}({1.x!r}, {1.y!r}, {1.z!r})'.format(type(self), self)

    def __str__(self):
        return 'Point({0.x!r}, {0.y!r}, {0.z!r})'.format(self)

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y, self.z + other.z)

    def __sub__(self, other):
        return Point(self.x - other.x, self.y - other.y, self.z - other.z)

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
            and self.__dict__ == other.__dict__)

    def __ne__(self, other):
        return not self.__eq__(other)

    @property
    def dist_from_origin(self):
        """returns the Euclidean distance from origin"""
        return _np.sqrt(self.x**2 + self.y**2 + self.z**2)

    def get_dist_from_point(self, other):
        """returns the Euclidean distance from another point"""
        s = self - other
        return _np.sqrt(s.x**2 + s.y**2 + s.z**2)

class Vector:
    """Three dimensional vector class"""

    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return '{0.__name__}({1.x!r}, {1.y!r}, {1.z!r})'.format(type(self), self)

    def __add__(self, other):
        """vector addition"""
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

    def __sub__(self, other):
        """vector substraction"""
        return Vector(self.x - other.x, self.y - other.y, self.z - other.z)

    def __abs__(self):
        """absolute value"""
        return (self.x **2 + self.y **2 + self.z **2) **0.5

    def __mul__(self, scalar):
        """scalar multiplication"""
        return Vector(scalar*self.x, scalar*self.y, scalar*self.z)

    def __rmul__(self, scalar):
        return Vector(scalar*self.x, scalar*self.y, scalar*self.z)

    def __bool__(self):
        """returns true if vector magnitude is not zero"""
        return bool(self.x or self.y or self.z)

    def __getitem__(self, position):
        """to support indexing and functions such as list(Vector(1, 2, 3))"""
        return list((self.x, self.y, self.z))[position]

#%% Test functions
def test_Point_class():
    p = Point()
    _nt.assert_array_equal((0.0, 0.0, 0.0), (p.x, p.y, p.z))
    p.x, p.y, p.z = 2, 3, 4
    _nt.assert_array_equal((2.0, 3.0, 4.0), (p.x, p.y, p.z))
    q = Point(10, 20, 30)
    s = p + q
    assert isinstance(s, Point)
    _nt.assert_array_equal((p.x + q.x, p.y + q.y, p.z + q.z), (s.x, s.y, s.z))
    # Test methods
    po = p.dist_from_origin
    _nt.assert_almost_equal(po, 5.38516480713)
    pq = p.get_dist_from_point(q)
    qp = q.get_dist_from_point(p)
    assert pq == qp
    _nt.assert_almost_equal(pq, 32.0780298647)
    # Test equality
    p = Point(3, 4, 5)
    q = Point(3, 4, 5)
    assert p is not q  # p and q are different objects
    assert p == q      # p and q are the same points
    l = Point()
    assert p != l
    print('Point class test successful')

def test_Vector_class():
    vec = Vector()
    _nt.assert_array_equal((0.0, 0.0, 0.0), (vec.x, vec.y, vec.z))
    _nt.assert_equal(True, isinstance(vec, Vector), 'Vector instance test failed')
    vec1 = Vector(1, 2, 3)
    _nt.assert_equal(True, isinstance(list(vec1), list), 'List instance test failed')
    _nt.assert_equal(2, vec1[1], 'Vector indexing test failed')
    vec2 = Vector(4, 5, 6)
    _nt.assert_array_equal(list((5, 7, 9)), list(vec1 + vec2), 'Vector addition test failed')
    _nt.assert_array_equal(list((-3, -3, -3)), list(vec1 - vec2), 'Vector substraction test failed')
    _nt.assert_array_equal(list((2, 4, 6)), list(2*vec1), 'Vector scalar pre-multiplication test failed')
    _nt.assert_array_equal(list((2, 4, 6)), list(vec1*2), 'Vector scalar post-multiplication test failed')
    vec3 = Vector(-1, 2, -3)
    _nt.assert_array_equal(_np.sqrt(vec3[0]**2 + vec3[1]**2 + vec3[2]**2), abs(vec3), 'Vector absolute test failed')
    _nt.assert_equal(True, bool(vec1), 'Vector bool test 1 failed')
    _nt.assert_equal(False, bool(vec), 'Vector bool test 2 failed')
    print('Vector class test successful')

if __name__ == '__main__':
    import numpy.testing as _nt
    from numpy import set_printoptions
    set_printoptions(precision=4, linewidth=85)  # for visual output in manual tests.
    # test functions
    test_Point_class()
    test_Vector_class()


#!/usr/bin/env python
'''
  pearson correlation
'''

import argparse
import csv
import logging
import sys

import numpy as np
import scipy.stats

def correlation(values1, values2):
  logging.info('starting: %i values vs %i values', len(values1), len(values2))
  logging.debug('group 1: %s; group 2: %s', ' '.join(values1), ' '.join(values2))

  if len(values1) == 0 or len(values2) == 0:
    logging.fatal('empty groups')
    return

  num1 = [float(x) for x in values1]
  num2 = [float(x) for x in values2]

  sys.stdout.write('pearson\tp-value\tv1u\tv1sd\tv1min\tv1max\tv1n\tv2u\tv2sd\tv2min\tv2max\tv2n\n')

  if all([num1[0] == x for x in num1 + num2]):
    logging.info('all values equal')
    sys.stdout.write('0\t1\t{}\t0\t{}\t{}\t{}\t{}\t0\t{}\t{}\t{}\n'.format(num1[0], num1[0], num1[0], len(num1), num1[0], num1[0], num1[0], len(num2)))
    return

  result = scipy.stats.pearsonr(num1, num2)

  sys.stdout.write('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n'.format(result[0], result[1], np.mean(num1), np.std(num1), min(num1), max(num1), len(num1), np.mean(num2), np.std(num2), min(num2), max(num2), len(num2)))

  logging.info('done')

def read_csv(fh, col1, col2):
  logging.debug('reading stdin...')
  values1 = []
  values2 = []
  for row in fh:
    values1.append(row[col1])
    values2.append(row[col2])
  correlation(values1, values2)

if __name__ == '__main__':
  parser = argparse.ArgumentParser(description='Measure correlation')
  parser.add_argument('--values1', required=False, nargs='+', help='group 1')
  parser.add_argument('--values2', required=False, nargs='+', help='group 2')
  parser.add_argument('--col1', required=False, help='stdin table')
  parser.add_argument('--col2', required=False, help='stdin table')
  parser.add_argument('--delimiter', required=False, default='\t', help='stdin table')
  parser.add_argument('--verbose', action='store_true', help='more logging')
  args = parser.parse_args()
  if args.verbose:
    logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG)
  else:
    logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)

  if args.values1 is not None and args.values2 is not None:
    correlation(args.values1, args.values2)
  else:
    read_csv(csv.DictReader(sys.stdin, delimiter=args.delimiter), args.col1, args.col2)


#
# Cannon ball trajectory computed via Euler approximation
#
# assumes: i) drag force F = - B_2 * v^2
#          ii) isothermal air density model: rho(y) = rho(0) * exp(-y / y0)
#
# by Denes Molnar for PHYS 580, Fall 2020

import math
import numpy as np

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

# computes arrays of x,y for parameters v0, theta, B2/m, y0scale, dt
#
def computeTrajectory(v0 = 700., theta = 45., B2_m = 4e-5, y0scale = 1e4, dt = 0.01):
   # convert to Cartesian initconds
   x0 = 0.
   y0 = 0.
   vx = v0 * math.cos(theta / 180. * math.pi);
   vy = v0 * math.sin(theta / 180. * math.pi);

   maxr = v0 * v0 / g   # max range of shell, in vaccuum (for automatic horizontal plot range)
   maxt = maxr / vx     # flight time at maxr, in vacuum (for atomatic calculation end time)
   nsteps = math.ceil(maxt / dt)   # time steps

   # allocate storage
   # - only position is stored (needed for plotting)
   x = np.zeros(nsteps + 1)
   y = np.zeros(nsteps + 1)

   # solve using Euler method
   for i in range(nsteps):
      x[i + 1] = x[i] + vx * dt
      y[i + 1] = y[i] + vy * dt
      v = math.sqrt(vx**2 + vy**2)
      fD_over_v = B2_m * v * math.exp(-y[i] / y0scale)    # isothermal model, hardcoded
      vx = vx -      fD_over_v * vx  * dt
      vy = vy - (g + fD_over_v * vy) * dt
      if y[i + 1] <= 0.:   # stop calculation at step (i+1) if y_i is below ground
         break

   # adjust last point to match interpolated range
   xmax = (y[i + 1] * x[i] - y[i] * x[i + 1] ) / (y[i + 1] - y[i])
   x[i + 1] = xmax  # adjust  last point to keep y >= 0 in plots
   y[i + 1] = 0.

   # return appropriately truncated arrays
   return x[:(i+2)], y[:(i+2)]

# physical parameters and initial conditions (units are in [] brackets)
#
#   v0 [m/s], theta [degrees], B2/m  [1/m],  y0 [m]
#
# some reasonable choices are B2/m = 4x10^(-5), y0 = 10^4
#
v0      = float( input('initial speed [m/s]: ') )
theta   = float( input('shooting angle [degrees]: ') )
B2_m    = float( input('B2/m [1/m]: ') )
y0scale = float( input('characteristic height in atmospheric pressure [m]: ') )
g       = 9.8   # gravitational acceleration [m/s^2]

# computational parameters: dt[s], nsteps (nsteps is autodetermined)
dt = float( input('dt [s]: ') )

# compute trajectory with Euler approximation
x,y = computeTrajectory(v0, theta, B2_m, y0scale, dt)

# y vs x plot
plt.xlabel('x [m]')    # horizontal position
plt.ylabel('y [m]')    # vertical position
titleString  = 'dt=' + str(dt) + ", v0=" + str(v0) + ", B2/m=" + str(B2_m)
titleString += ", h=" + str(y0scale) + ", theta=" + str(theta)
plt.title(titleString) # plot title
plt.plot(x, y, label = "Euler")
plt.legend()             # create legends
plt.show()               # show plot

#EOF


import numpy as np
import matplotlib.pyplot as plt

# Construct xi
dx = 0.10
xi = np.arange(0, np.pi/2, dx)

# Function values
fi = np.sin(xi)
# Derivative
dfi = (fi[2:] - fi[:-2]) / (2.0*dx)

# Compare to cos. Note that derivative was not defined in end points
f_ref = np.cos(xi[1:-1])
print("Mean squared difference:")
print(np.sqrt(np.sum((dfi - f_ref)**2)))
plt.plot(xi[1:-1], dfi, label="sin'")
plt.plot(xi[1:-1], f_ref, label="cos")
plt.legend()
plt.show()


'''
Collated by Ching-Shih Tsou 鄒慶士 博士 (Ph.D.) Distinguished Prof. at the Department of Mechanical Engineering/Director at the Center of Artificial Intelligence & Data Science (機械工程系特聘教授兼人工智慧暨資料科學研究中心主任), MCUT (明志科技大學); Prof. at the Institute of Information & Decision Sciences (資訊與決策科學研究所教授), NTUB (國立臺北商業大學); the Chinese Academy of R Software (CARS) (中華R軟體學會創會理事長); the Data Science and Business Applications Association of Taiwan (DSBA) (臺灣資料科學與商業應用協會創會理事長); the Chinese Association for Quality Assessment and Evaluation (CAQAE) (中華品質評鑑協會常務監事); the Chinese Society of Quality (CSQ) (中華民國品質學會大數據品質應用委員會主任委員
Notes: This code is provided without warranty.
'''

# Take an arbitrary cosine function of the form x(t) = Acos(2π fct +φ) and proceed step by step as follows
# • Represent the signal x(t) in computer memory (discrete-time x[n]) and plot the signal in time domain
# • Represent the signal in frequency domain using FFT (X[k])
# • Extract magnitude and phase information from the FFT result
# • Reconstruct the time domain signal from the frequency domain samples

from scipy.fftpack import fft, ifft, fftshift, ifftshift
import numpy as np
import matplotlib.pyplot as plt
A = 0.5 # amplitude of the cosine wave
fc = 10 # frequency of the cosine wave in Hz
phase = 30 # desired phase shift of the cosine in degrees
fs = 32*fc # sampling frequency with oversampling factor 32
t = np.arange(start = 0,stop = 2,step = 1/fs) # 2 seconds duration
phi = phase*np.pi/180; # convert phase shift in degrees in radians 轉換為弳/弧度量
x = A*np.cos(2*np.pi*fc*t+phi) # time domain signal with phase shift

N = 256 # FFT size
X = 1/N*fftshift(fft(x, N)) # N-point complex DFT

df = fs/N # frequency resolution
sampleIndex = np.arange(start = -N//2, stop = N//2) # // for integer division (-128, 127)
f = sampleIndex*df # x-axis index converted to ordered frequencies

fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4, ncols=1)
ax1.plot(t,x) # plot time domain representation
ax1.set_title(r'$x(t) = 0.5 cos (2 \pi 10 t + \pi/6)$')
ax1.set_xlabel('time (t seconds)');ax1.set_ylabel('x(t)')

ax2.stem(f, abs(X), use_line_collection=True) # magnitudes vs frequencies
ax2.set_xlim(-30, 30)
ax2.set_title('Amplitude spectrum')
ax2.set_xlabel('f (Hz)');ax2.set_ylabel(r'$ \left| X(k) \right|$')

phase=np.arctan2(np.imag(X),np.real(X))*180/np.pi # phase information
ax3.plot(f,phase) # phase vs frequencies

X2 = X #store the FFT results in another array
# detect noise (very small numbers (eps)) and ignore them
threshold = max(abs(X))/10000; # tolerance threshold
X2[abs(X)<threshold]=0 # maskout values below the threshold
phase=np.arctan2(np.imag(X2),np.real(X2))*180/np.pi # phase information
ax4.stem(f,phase, use_line_collection=True) # phase vs frequencies
ax4.set_xlim(-30, 30);ax4.set_title('Phase spectrum')
ax4.set_ylabel(r"$\angle$ X[k]");ax4.set_xlabel('f(Hz)')
fig.show()

X[0:5]

np.arctan2(np.imag(X[0:5]),np.real(X[0:5]))

#### Reconstructing the time domain signal from the frequency domain samples
x_recon = N*ifft(ifftshift(X),N) # reconstructed signal
t = np.arange(start = 0,stop = len(x_recon))/fs # recompute time index

fig2, ax5 = plt.subplots()
ax5.plot(t,np.real(x_recon)) # reconstructed signal
ax5.set_title('reconstructed signal')
ax5.set_xlabel('time (t seconds)');ax5.set_ylabel('x(t)');
fig2.show()

#### Reference:
# Viswanathan, Mathuranathan, Digital Modulations using Python, December 2019.


from numpy import array, zeros, float, dot
from copy import copy
import scipy.linalg
import numpy
import time

def GaussJordan(A,b):

    n,m = A.shape
    C = zeros((n,m+1),float)
    C[:,0:n],C[:,0:n] = A, b

    for j in range(n):
        # partial pivoting.
        p = j
        # look for alternate pivot by searching for largest element in column
        for i in range(j+1,n):
            if abs(C[i,j]) > abs(C[p,j]): p = i
        if abs(C[p,j]) < 1.0e-16:
            print "matrix is singular" # its determinant is 0.
            return b
        # swap rows to get largest magnitude element on the diagonal
        C[p,:],C[j,:] = copy(C[j,:]),copy(C[p,:])

        pivot = C[j,j]
        C[j,:] = C[j,:] / pivot
        for i in range(n):
            if i == j: continue
            C[i,:] = C[i,:] - C[i,j]*C[j,:]
    I,x = C[:,0:n],C[:,n]
    return x

if __name__ == '__main__':

    import numpy as np
    data = np.zeros((100,100))
    data[np.arange(99), np.arange(99)+1] = [-1]
    data[np.arange(99)+1, np.arange(99)] = [-1]
    data[np.arange(100), np.arange(100)] = [-2]
    A = data

    data = np.zeros((100,1))
    data[np.arange(98)+1, np.arange(1)] = [1]
    data[np.arange(1), np.arange(1)] = [2]
    data[np.arange(1)+99, np.arange(1)] = [2]
    b =  data

    print "A : \n", A
    print "b : \n", b
    x = GaussJordan(A,b)
    print "x: \n", x
    print "\n\n\n"
    print "-"*40
    print "Ax : \n", dot(A,x)

    print '\n\nresidual', scipy.linalg.norm(numpy.dot(A, x) - b)/scipy.linalg.norm(A)
    tic = time.clock()
    toc = time.clock()
    print "Processing time is : %f" %(toc - tic)


#!/usr/bin/env python3

"""
    Exercise 2.13 Cuadratic Equation Ax**2+Bx+C=0
    Probability it has real roots (B**2-$AC >=0) when A, B, C are selected randomly
    in interval (-q,q) or integers in -q..q
    Solve for q = 1; 10; 100; 1000; 10000
"""

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

def simulate_AX2BXC_real(q, verbose):
    """(real, bool)
    Carry out simulation. Find A, B, C randomly in (-q,q)
    """
    A, B, C = np.random.random(3) * 2 * q - q
    discriminator = B ** 2 - 4 * A * C
    real_root = ( discriminator >= 0)
    if verbose:
        print('REAL q={} A {} B {} C {} discriminator {}  {}'.format(q,A,B,C,discriminator,real_root))
    return real_root

def simulate_AX2BXC_int(q, verbose):
    """(real, bool)
    Carry out simulation. Find A, B, C randomly in (-Q,Q)
    """
    A, B, C = np.random.randint(low=-q, high=q+1, size=3)
    discriminator = B ** 2 - 4 * A * C
    real_root = ( discriminator >= 0)
    if verbose:
        print('INT  q={} A {} B {} C {} discriminator {}  {}'.format(q,A,B,C,discriminator,real_root))
    return real_root

def main():
    # Get command-line arguments
    parser = argparse.ArgumentParser(
        description='simulate the Newspaper arrival problem')
    parser.add_argument('--q', default=1, type=int, metavar='int',
                        help='Interval q (-q,q)')
    parser.add_argument('--trials', default=10000, type=int, metavar='int',
                        help='number of trials to perform')
    parser.add_argument('--real', default=True, action='store_true',
                        help='use (-q,q) as real numbers, otherwise use -Q..Q as Integers')
    parser.add_argument('--verbose', default=False, action='store_true',
                        help='display the results of each trial')
    args = parser.parse_args()

    real_roots = 0
    intg_roots = 0
    for i in range(args.trials):
        # First, do a trial where the contestant never switches.
        real_root = simulate_AX2BXC_real(args.q, verbose=args.verbose)
        if real_root: real_roots += 1
        real_root = simulate_AX2BXC_int(args.q, verbose=args.verbose)
        if real_root: intg_roots += 1

    print('Q={0} REAL has real roots  {1:,} times out of {2:,} ({3:.2f}% of the time)'.format(
            args.q, real_roots, args.trials, (real_roots / args.trials * 100) ))
    print('Q={0} INTG has real roots  {1:,} times out of {2:,} ({3:.2f}% of the time)'.format(
            args.q, intg_roots, args.trials, (intg_roots / args.trials * 100) ))

if __name__ == '__main__':
    main()


#1. Import the NUMPY package under the name np.
import numpy as np

#2. Print the NUMPY version and the configuration.
print (np.__version__)

#3. Generate a 2x3x5 3-dimensional array with random values. Assign the array to variable "a"
# Challenge: there are at least three easy ways that use numpy to generate random arrays. How many ways can you find?
a = np.random.random ((2,3,5))

#4. Print a.
print(a)

#5. Create a 5x2x3 3-dimensional array with all values equaling 1.
#Assign the array to variable "b"
b = np.ones((5,2,3))

#6. Print b.
print(b)

#7. Do a and b have the same size? How do you prove that in Python code?
a = np.random.random ((2,3,5))
print(a.size)

b = np.ones((3,5,2))
print(b.size)
#Yes, both of them have the same size

#8. Are you able to add a and b? Why or why not?

#no  because they have different rows and columns

#9. Transpose b so that it has the same structure of a (i.e. become a 2x3x5 array). Assign the transposed array to varialbe "c".
a = np.random.random ((2,3,5))
b = np.ones((5,2,3))
c = b.transpose((1,2,0))

print(a)
print(b)
print(c)

#10. Try to add a and c. Now it should work. Assign the sum to varialbe "d". But why does it work now?

d = (np.add(a, c))
print(c)
#now it works because both matrixes have the same structure, two subgroups with 3 rows and five columns each

#11. Print a and d. Notice the difference and relation of the two array in terms of the values? Explain.
print(a)
print(d)

#The resulting matrix has the same structure than the previous one, but all the values are now increased by one

#12. Multiply a and c. Assign the result to e.
e = (np.multiply(a, c))
print(e)

#13. Does e equal to a? Why or why not?

#Yes, they are both tha same as yu are multiplying by one. It can be confirmed finding the difference by  doing:
z = (np.subtract(e, a))
print(z)

#14. Identify the max, min, and mean values in d. Assign those values to variables "d_max", "d_min", and "d_mean"

d_mean = (np.mean(d))
d_max = (np.max(d))
d_min = (np.min(d))

print(d_mean)
print(d_min)
print(d_max)

#15. Now we want to label the values in d. First create an empty array "f" with the same shape (i.e. 2x3x5) as d using `np.empty`.

f = np.empty((2,3,5))

f[d<d_mean]=25
f[d>d_mean]=75
f[d==d_min]=0
f[d==d_mean]=50
f[d==d_max]=100

#16. Populate the values in f. For each value in d, if it's larger than d_min but smaller than d_mean, assign 25 to the corresponding value in f.
# If a value in d is larger than d_mean but smaller than d_max, assign 75 to the corresponding value in f.
# If a value equals to d_mean, assign 50 to the corresponding value in f.
# Assign 0 to the corresponding value(s) in f for d_min in d.
# Assign 100 to the corresponding value(s) in f for d_max in d.
# In the end, f should have only the following values: 0, 25, 50, 75, and 100.
# Note: you don't have to use Numpy in this question.
f[d<d_mean]=25
f[d>d_mean]=75
f[d==d_min]=0
f[d==d_mean]=50
f[d==d_max]=100

#17. Print d and f. Do you have your expected f?

print(d)
print(f)

"""
For instance, if your d is:
array([[[1.85836099, 1.67064465, 1.62576044, 1.40243961, 1.88454931],
        [1.75354326, 1.69403643, 1.36729252, 1.61415071, 1.12104981],
        [1.72201435, 1.1862918 , 1.87078449, 1.7726778 , 1.88180042]],
       [[1.44747908, 1.31673383, 1.02000951, 1.52218947, 1.97066381],
        [1.79129243, 1.74983003, 1.96028037, 1.85166831, 1.65450881],
        [1.18068344, 1.9587381 , 1.00656599, 1.93402165, 1.73514584]]])
Your f should be:
array([[[ 75.,  75.,  75.,  25.,  75.],
        [ 75.,  75.,  25.,  25.,  25.],
        [ 75.,  25.,  75.,  75.,  75.]],
       [[ 25.,  25.,  25.,  25., 100.],
        [ 75.,  75.,  75.,  75.,  75.],
        [ 25.,  75.,   0.,  75.,  75.]]])
"""

"""
#18. Bonus question: instead of using numbers (i.e. 0, 25, 50, 75, and 100), how to use string values
("A", "B", "C", "D", and "E") to label the array elements? You are expecting the result to be:
array([[[ 'D',  'D',  'D',  'B',  'D'],
        [ 'D',  'D',  'B',  'B',  'B'],
        [ 'D',  'B',  'D',  'D',  'D']],
       [[ 'B',  'B',  'B',  'B',  'E'],
        [ 'D',  'D',  'D',  'D',  'D'],
        [ 'B',  'D',   'A',  'D', 'D']]])
Again, you don't need Numpy in this question.
"""


# region Starting Values
# need for multiplicating matrices in the end
import numpy as np
np.set_printoptions(suppress=True)

matrix = [[3.81, 0.25, 1.28, 2.75],
          [2.25, 1.32, 6.58, 0.49],
          [5.31, 8.28, 0.98, 1.04],
          [11.39, 2.45, 3.35, 2.28]]

rightPart = [4.21, 8.47, 2.38, 12.48]

matrixDiagonal =    [[15.2, 4.63, 2.7, 5.03],
                    [2.25, 6.58, 1.32, 0.49],
                    [5.31, 0.98, 8.28, 1.04],
                    [0, 0.119454, -0.426777, 1.48919]]

rightPartDiagonal = [16.69, 8.47, 2.38, 0.026518]

N = len(matrixDiagonal)
difference = [0] * N
X = [0] * N
rounding = 6
vectorToShow = 3
doOperations = True
epsilonValue = 0.000001 # 10^(-6)
iterations = 0

# endregion Starting Values

# copy matrix to create extended matrix
extendedMatrix = list(map(list, matrixDiagonal))

# region Prints

# Print vector
def PrintVector(vectorName,vector):
    print("\n",vectorName,"=")
    for i in vector:
        print(i, end = " \t")
    print()

# print matrix
def PrintMatrix(matrixName,matrix):
    print("\n",matrixName,"=")
    for i in matrix:
        for j in i:
            print(j, end=" \t")
            if len(str(j)) <= 5:
                print(end=" \t")
        print()

# print additional parametrs
def PrintParametrs():
    print("\n Rows =", rows)
    print(" Columns =", columns)
    print(" Exteneded Rows =", extendedRows)
    print(" Exteneded Columns =", extendedColumns)
    print(" n =", N)

# just printing
def PrintAll():
    PrintMatrix("Start Matrix",matrixDiagonal)

    PrintVector("Right Part", rightPartDiagonal)

    PrintParametrs()

    PrintMatrix("Extended Matrix",extendedMatrix)

# endregion Prints

# region Check the results
def Residual():
    multiplied = np.round(np.dot(matrixDiagonal,X),rounding)

    R = np.round(np.subtract(rightPartDiagonal,multiplied),rounding)

    print("R =\n",R)

# endregion Check the results

# add right part to main matrix
RPCounter = 0
while RPCounter < len(rightPartDiagonal):
    extendedMatrix[RPCounter].append(rightPartDiagonal[RPCounter])
    RPCounter += 1

# region Getting rows and columns

rows = len(matrixDiagonal)
columns = len(matrixDiagonal)

extendedRows = len(extendedMatrix)
extendedColumns = len(extendedMatrix)+1

# endregion Getting rows and columns

PrintAll()

while doOperations:
    tempX = X.copy()
    for c in range(0, N):
        #temporal variable to store rightPart element
        element  = rightPartDiagonal[c]

        # calculate every element in array
        for z in range(0, N):
            if(c != z):
                element  = element - (matrixDiagonal[c][z] * X[z])
        # create new value
        X[c] = round(element  / matrixDiagonal[c][c], rounding)

    # compare two vectors
    for k in range(N):
        difference[k] = abs(tempX[k] - X[k])
        if max(difference) < epsilonValue:
            doOperations = False

    # show first three iterations of vector X
    if iterations < vectorToShow:
        PrintVector("X", X)
    iterations = iterations + 1
    if doOperations:
        Residual()

print("\nFinal results:")
PrintVector("X", X)
Residual()
print("Total iterations = ", iterations)


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

import numpy as np
import numpy.matlib as npmatlib

def print_this_matrix(given_matrix):
  for i in range(len(given_matrix)):
   for j in range(len(given_matrix[i])):
    print (given_matrix[i][j]," ",end="")
   print()
  print("\n")

def print_this_string_matrix(given_matrix):
  for i in range(len(given_matrix)):
   for j in range(len(given_matrix[i])):
    print (given_matrix[i][j],end="")
   print()
  print("\n")

print("generatng matrix for given n x m - with given default values")
print(npmatlib.ones((5,6)))
print("generatng matrix for given n x m - with given default values")
print(npmatlib.zeros((4,3)))

# returns a matrix with 1 along the diagonal elements and the zeros elsewhere.
# K =  start index to start first 1
print(np.matlib.eye(n = 5, M = 8, k = 6, dtype = float))
print(np.matlib.eye(n = 5, M = 5, k = 3, dtype = float))

print("generatng identity matrix for given n x n - with given default values")
print(np.matlib.identity(5, dtype = float))

print("generatng identity matrix for given n x n - with given default values")
print(np.matlib.rand(3,3))

print("generatng matrix for given n x m - with random values")
print(np.matlib.rand(3,3))

print("generatng matrix from given array")
arr_now = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
print(np.matrix(arr_now))
arr_now = np.array([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]])
print(np.matrix(arr_now))

arr_now = np.array([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]])
print("as matrix from given array -- \n", np.asmatrix(arr_now))

matrx_now = np.matlib.ones((5,6))
print("as array from given matrix -- \n", np.asarray(matrx_now))

# inner product
arr_normal = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
print("arr_normal =   \n",arr_normal)
print("inner product  \n",np.inner(arr_normal,arr_normal))

arr_2d_1 = [[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11],
            [12, 13, 14, 15]]
arr_2d_2 = [[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11],
            [12, 13, 14, 15]]
print("arr_2d_1 =   \n",arr_2d_1)
print("arr_2d_2 =   \n",arr_2d_2)
print("np.matmul(arr_2d_1,arr_2d_2) =   \n",np.matmul(arr_2d_1,arr_2d_2))

# solving linear equation
aaa=   2.0
bbb= - 9.0
ccc=  55.0
print(( 9 * aaa) + (    bbb) - (10 * ccc)) # -541
print((-8 * aaa) - (5 * bbb) - ( 0 * ccc)) #  029
print(( 9 * aaa) + (3 * bbb) + ( 1 * ccc)) #  046

eq1      = np.array([[9,1,-10],[-8,-5,0],[9,3,1]])
eq_total = np.array([-541,29,46])
print("np.linalg.solve(eq1, eq_total) =   \n",np.linalg.solve(eq1, eq_total))

arr_extreme = np.array([[ 4,   5,  6,   7],
                        [ 3,  -1, -2,  -3],
                        [ 8,   9,  10,  11],
                        [12,   13, 14,  15]])
print("np.amax(arr_extreme)                    --->",np.amax(arr_extreme))
print("np.amax(arr_extreme, axis=0)--vertical  --->",np.amax(arr_extreme, axis=0))
print("np.amax(arr_extreme, axis=1)--horizontal--->",np.amax(arr_extreme, axis=1))
print("np.amax(arr_extreme, axis=1)--horizontal--->",np.amax(arr_extreme, axis=1))

# flatten : return a copy of the array collapsed into one dimension
arr_extreme.flatten()
print("just index of sorted element")
print("np.argmax(arr_extreme, axis=1)--horizontal--->",np.argmax(arr_extreme, axis=1))

print("numbers sorting using numpy--->")
arr_tosort = np.array([[ 4.,   5.,  6,  -7],
                       [ 3.,  -1., -2,  -3],
                       [ 8.,   9.,  10, -11],
                       [12.,   13.,-14,  15]],dtype='float64')
print_this_matrix(arr_tosort)

print("np.sort() does not change original array --->\n")
print("np.sort(arr_tosort)                          --->\n",np.sort(arr_tosort))
print("np.sort(arr_tosort,axis = 0)   vertically    --->\n",np.sort(arr_tosort,axis = 0))
print("np.sort(arr_tosort,axis = 1)   horizontally  --->\n",np.sort(arr_tosort,axis = 1))
print("sort on a row --->\n",arr_tosort[arr_tosort[:,1].argsort()])

print_this_matrix(arr_tosort)
print("array_name.sort() changes original array --->")
arr_tosort.sort()
print("after arr_tosort.sort() --->")
print_this_matrix(arr_tosort)
print("\n")

print("string sorting using numpy--->")
input_string_array = np.array(["year","month","eye","i","stream","key","house"])
print("input string array")
print_this_string_matrix(input_string_array)
input_string_array_sorted_index = list(map(lambda x: len(x), input_string_array))
output_string_array = input_string_array[np.argsort(input_string_array_sorted_index)]
print("output string array sorted ---> ")
print_this_string_matrix(output_string_array)
print("\n")

arr_where = np.array([[ 4.,   5.,  6,  -7],
                      [ 3.,  -1., -2,  -3],
                      [ 8.,   9.,  10, -11],
                      [12.,   13.,-14,  15]],dtype='float64')
print_this_matrix(arr_where)
arr_idx_greater_than = np.where(arr_where > 5.5)
print("indices of elements greater than 5.5     --->",arr_idx_greater_than)
print("all actual elements greater than 5.5     --->",arr_where[arr_idx_greater_than])
print("shape of resultant array is always 1d    --->",arr_where[arr_idx_greater_than].shape)
print("\n")

print("numpy extract elements out of an array with a condition")
arr_extract = np.array([[ 4.,   5.,  6,  -7],
                        [ 3.,  -1., -2,  -3],
                        [ 8.,   9.,  10, -11],
                        [12.,   13.,-14,  15]],dtype='float64')
print_this_matrix(arr_where)
condition = np.mod(arr_extract,2.0) == 0
print("condition = np.mod(arr_extract,2.0) == 0  ----> ",np.mod(arr_extract,2.0) == 0)
print("np.extract(condition, arr_extract)        ----> ",np.extract(condition, arr_extract))
print("\n")

print("save array output to a .npy file")
arr_saveme = np.array([[ 4.,   5.,  6,  -7],
                       [ 3.,  -1., -2,  -3],
                       [ 8.,   9.,  10, -11],
                       [12.,   13.,-14,  15]],dtype='float64')
np.save('__arr_saveme',arr_saveme)
print("load array output from a .npy file \n",np.load('__arr_saveme.npy'))
print("\n")


from manim import *
import numpy as np
from itertools import product

pMatrix = lambda mat, *args, **kwargs: Matrix(
    mat, *args, **kwargs, left_bracket="(", right_bracket=")"
)

class ShowMatrix(Scene):
    def construct(self):
        mat = pMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

        self.play(Write(mat), run_time=2)
        self.wait()
        self.play(Indicate(mat))
        self.wait()

class MatrixComponents(Scene):
    def construct(self):
        mat = pMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
        brakets = mat.get_brackets()
        rows = mat.get_rows()
        columns = mat.get_columns()

        self.play(FadeIn(mat))
        self.wait()
        for entry in mat[0]:
            self.play(Indicate(entry), run_time=0.5)
        self.wait()
        self.play(Indicate(brakets[0]))
        self.play(Indicate(brakets[1]))
        self.wait()
        self.play(Indicate(rows[0]))
        self.play(Indicate(rows[1]))
        self.play(Indicate(rows[2]))
        self.wait()
        self.play(Indicate(columns[0]))
        self.play(Indicate(columns[1]))
        self.play(Indicate(columns[2]))
        self.wait()

class MatrixTranspose(Scene):
    def construct(self):
        # dimension of matrix : n * m
        n, m = 4, 5

        npmat = np.array([[(i + 1) ** j for j in range(m)] for i in range(n)])

        mat1 = pMatrix(npmat)
        mat2 = pMatrix(npmat.T)

        x1 = mat1[0][0].get_x()
        x2 = mat2[0][0].get_x()
        y1 = mat1[0][0].get_y()
        y2 = mat2[0][0].get_y()

        xm = (x1 + x2) / 2
        ym = (y1 + y2) / 2

        mat1.shift(RIGHT * (xm - x1) + UP * (ym - y1))
        mat2.shift(RIGHT * (xm - x2) + UP * (ym - y2))

        # self.add(mat1, mat2)
        # self.wait()
        self.play(FadeIn(mat1))
        self.wait()
        self.play(FadeOut(mat1[1]), run_time=0.5)
        self.play(FadeOut(mat1[2]), run_time=0.5)
        self.wait()

        transposeAnimations = [
            ReplacementTransform(mat1.get_rows()[i][j], mat2.get_rows()[j][i])
            for i, j in product(range(n), range(m))
        ]
        self.play(*transposeAnimations, run_time=2)
        self.wait()
        self.play(FadeIn(mat2[1]), run_time=0.5)
        self.play(FadeIn(mat2[2]), run_time=0.5)
        self.wait()

class MatrixMultiplication(Scene):
    def construct(self):
        n, k, m = 3, 5, 4
        np.random.seed(0)
        npmat1 = np.random.randint(-10, 10, size=(n, k))
        npmat2 = np.random.randint(-10, 10, size=(k, m))
        npmat3 = npmat1 @ npmat2

        mat1, mat2, mat3 = pMatrix(npmat1), pMatrix(npmat2), pMatrix(npmat3)
        mat1.scale(0.6)
        mat2.scale(0.6)
        mat3.scale(0.6)

        eq = VGroup(mat1, mat2, MathTex("="), mat3)
        eq.arrange(RIGHT)

        rowRectangles = [
            BackgroundRectangle(
                row, color=YELLOW, fill_opacity=0.5, corner_radius=0.05, buff=0.1
            )
            for row in mat1.get_rows()
        ]
        columnRectangles = [
            BackgroundRectangle(
                column, color=YELLOW, fill_opacity=0.5, corner_radius=0.05, buff=0.1
            )
            for column in mat2.get_columns()
        ]

        tmpmat1, tmpmat2 = mat1.copy(), mat2.copy()
        tmpgroup = VGroup(tmpmat1, tmpmat2)
        tmpgroup.arrange(RIGHT)

        self.play(Create(tmpgroup), run_time=2)
        self.wait()
        self.play(
            ReplacementTransform(tmpmat1, mat1), ReplacementTransform(tmpmat2, mat2)
        )
        self.wait()
        self.play(Create(eq[2]))
        self.play(FadeIn(eq[3][1]))
        self.play(FadeIn(eq[3][2]))
        self.wait()

        for i, j in product(range(n), range(m)):
            self.play(
                FadeIn(rowRectangles[i]), FadeIn(columnRectangles[j]), run_time=0.5
            )
            self.play(Write(mat3.get_rows()[i][j]))
            self.play(
                FadeOut(rowRectangles[i]), FadeOut(columnRectangles[j]), run_time=0.5
            )
            self.wait(0.1)
        self.wait()

class ElementaryRowOps(Scene):
    def construct(self):
        n,m = 4,5
        np.random.seed(0)


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

import numpy as np
import matplotlib.pyplot as plt

#%% simulate Brownian Motion
T = 4
N = 1001

t = np.linspace(0,T,N)
k = t[1]

num_trajectories = 1

dWt = np.random.randn(num_trajectories,N)*np.sqrt(k)
dWt[:,0] = 0

Wt = np.cumsum(dWt,axis=1)

plt.figure()
plt.plot(t,Wt.T,color='k',alpha=0.01)
plt.show()

#%% check statistics
mean = np.mean(Wt,axis=0)
var = np.var(Wt,axis=0)

plt.figure()
plt.plot(t,mean)
plt.show()

plt.figure()
plt.plot(t,var)
plt.show()

plt.figure()
plt.hist(Wt[:,-1])
plt.show()

#%% euler-maruyama method
def euler_maruyama(mu,sigma,x0,t,Wt):
    N = len(t)
    x = np.zeros(N)
    x[0] = x0
    for i in range(N-1):
        dt = t[i+1] - t[i]
        dWt = Wt[i+1] - Wt[i]
        x[i+1] = x[i] + mu(t,x[i])*dt + sigma(t,x[i])*dWt
    return x

#%% Geometric Brownian Motion
u = 1
s = 1

def mu(t,x):
    return u*x

def sigma(t,x):
    return s*x

def x_true_(x0,t,Wt):
    return x0*np.exp((u-s**2/2)*t+s*Wt)

#%% Solve over generated BM trajectories
x0 = 1
x_gbm = euler_maruyama(mu,sigma,x0,t,Wt[0])
x_true = x_true_(x0,t,Wt[0])

plt.figure()
plt.plot(t,x_gbm)
plt.plot(t,x_true)

#%% OU Process
theta = 10
u = 1
s = 0.5

def mu(t,x):
    return theta*(u-x)

def sigma(t,x):
    return s

#%% Solve over generated BM trajectories
x0 = 0
plt.figure()
for wt in Wt:
    x_ou = euler_maruyama(mu,sigma,x0,t,wt)
    plt.plot(t,x_ou,color='k',alpha=.01)
plt.show()


import numpy as np
import math
import time
def find_prime(n):
    flags = np.ones(n, dtype=np.int8)
    flags[:2] = 0
    max_num = math.floor(math.sqrt(n))
    for i in range(2, max_num):
        if flags[i]:
            flags[ [i + j for j in range(i, n - i, i)] ] = 0

    return [i for i in range(n) if flags[i] == 1]

s = time.time()
a = find_prime(100000)
e = time.time()
print('time = ', e - s)
print('found ', len(a), ' number')
# print(a)


import os
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as op
from ex2_utils import plotData, plotDecisionBoundary, sigmoid, predict

## Machine Learning Online Class - Exercise 2: Logistic Regression

def costFunction(initial_theta, X, y):
    m = y.size
    hx = sigmoid(X @ initial_theta)
    J = (- y @ np.log(hx) - (1 - y) @ np.log(1 - hx))/m
    grad = X.T @ (hx - y) / m
    return (J, grad)

# Load Data
#  The first two columns contains the exam scores and the third column
#  contains the label.
scriptdir = os.path.dirname(os.path.realpath(__file__))
data = np.loadtxt(scriptdir + '//ex2data1.txt', delimiter=',')
X = data[:,:-1]
y = data[:,-1]

# ==================== Part 1: Plotting ====================
#  We start the exercise by first plotting the data to understand the
#  the problem we are working with.

print('Plotting data with + indicating (y = 1) examples and o indicating (y = 0) examples.')

plotData(X, y)
# Labels and Legend
plt.legend(['Admitted', 'Not Admitted'])
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
plt.show()
input('\nProgram paused. Press enter to continue.\n')

# ============ Part 2: Compute Cost and Gradient ============
#  Setup the data matrix appropriately, and add ones for the intercept term
m, n = X.shape
# Add intercept term to x and X_test
X = np.c_[np.ones(m), X]

# Initialize fitting parameters
initial_theta = np.zeros(n + 1)

# Compute and display initial cost and gradient
cost, grad = costFunction(initial_theta, X, y)

print(f'Cost at initial theta (zeros): {cost}')
print('Expected cost (approx): 0.693')
print('Gradient at initial theta (zeros):')
print(grad)
print('Expected gradients (approx):\n -0.1000\n -12.0092\n -11.2628\n')

# Compute and display cost and gradient with non-zero theta
test_theta = [-24, 0.2, 0.2]
cost, grad = costFunction(test_theta, X, y)

print(f'Cost at test theta: {cost}')
print(f'Expected cost (approx): 0.218')
print(f'Gradient at test theta:')
print(grad)
print('Expected gradients (approx):\n 0.043\n 2.566\n 2.647\n')

input('Program paused. Press enter to continue.')

# ============= Part 3: Optimizing using fminunc  =============
Result = op.minimize(fun = costFunction, x0 = initial_theta, args = (X, y), method = 'TNC', jac = True)
cost = Result.fun
theta = Result.x
# Print theta to screen
print(f'Cost at theta found by minimize: {cost}')
print('Expected cost (approx): 0.203')
print(f'theta: {theta}')
print('Expected theta (approx):')
print(' -25.161\n 0.206\n 0.201\n')

# Plot Boundary
plotDecisionBoundary(theta, X, y)
# Labels and Legend

plt.legend(['Admitted', 'Not Admitted', 'Decision Boundary'])
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
plt.show()

input('Program paused. Press enter to continue.\n')

# ============== Part 4: Predict and Accuracies ==============
#  Predict probability for a student with score 45 on exam 1
#  and score 85 on exam 2

prob = sigmoid([1, 45, 85] @ theta)
print(f'For a student with scores 45 and 85, we predict an admission probability of {prob}')
print('Expected value: 0.775 +/- 0.002\n')

# Compute accuracy on our training set
p = predict(theta, X)

print(f'Train Accuracy: {np.mean((p == y)) * 100}')
print('Expected accuracy (approx): 89.0\n')


# coding: utf-8

# ## Creating, Adding, Split and Removing arrays
# Numpy, short for Numerical Python, is the fundamental package required for hight performance scientific computing and its best library to learn and apply on data science career.
# ### Here are the main steps we will go through
# * How to create array in numpy?
# * How to add two arrays together?
# * How to delete array in numpy?
# * Inserts values into arr given index
# * Split array in given index
#
# This is just little illustration.
#

# #### How to create array in numpy?
# arange([start,] stop[, step,][, dtype]) :
#
# arange() will create arrays with regularly incrementing values. Check the docstring for complete information on the various ways it can be used. A few examples will be given here:

# In[8]:

import numpy as np
# we can use the first argument [start]
arr = np.arange(5)
arr

# In[17]:

# we can pass [start] stop[step]
arr2 = np.arange(1, 10)
print("array containing [start(1) - end(10)]: ",arr2)

#apply step
arr3 = np.arange(1, 10, 2)
print("array containing [start(1) - end(10) - step(2)]: ", arr3)

# In[20]:

# we can print shape of the array and as well as dtype
shp = np.arange(1,10)
print("Shape of array: ",shp.shape )
# dtype
dty = np.arange(1,20)
print("Dtype: ", dty.shape)

# ##### creating 2D array
# np.array
#
# NumPy’s array class is called ndarray. It is also known by the alias array. Note that numpy.array is not the same as the Standard Python Library class array.array, which only handles one-dimensional arrays and offers less functionality. Check the docstring for complete information on the various ways it can be used.

# In[43]:

# we can create 2-dimention array
d_2 = np.array([[1,2,3],[4,5,6]])
d_2
print("2D shape: ", d_2.shape)
# we can use random function
rnd = np.random.random(9).reshape(3,3)
rnd
print("random array: ", rnd.shape)

# #### How to add two arrays together?
# numpy.concatenate((a1, a2, ...), axis=0)
#
# Join a sequence of arrays along an existing axis. Check the docstring for complete information on the various ways it can be used.

# In[57]:

array_1 = np.array([[1, 2], [3, 4]])
array_2 = np.array([[5, 6], [7, 8]])
array_1

# In[58]:

array_2

# In[54]:

# we can add array_2 as rows to the end of array_1
# axis 0 = rows
np.concatenate((array_1, array_2), axis=0)

# In[55]:

# we can add array_2 as columns to end of array_1
# axis 1 = columns
np.concatenate((array_1, array_2), axis=1)

# #### How to delete array in numpy?
# numpy.delete(arr, obj, axis=None)
#
# Return a new array with sub-arrays along an axis deleted. Check the docstring for complete information on the various ways it can be used.

# In[78]:

del_arry = np.array([[1,2,3],[4,5,6]])
del_arry

# In[77]:

# column 2: [3 and 6]
# we can delete columm on index 2 of array
del_arry = np.delete(del_arry, 2, axis=1)
del_arry

# In[79]:

# row 1: [4, 5, 6]
# we can delete row on index 1 of the array
del_arry = np.delete(del_arry, 1, axis=0)
del_arry

# #### Inserts values into arr given index?
# numpy.insert(arr, obj, values, axis=None)
#
# Insert values along the given axis before the given indices. Check the docstring for complete information on the various ways it can be used.

# In[94]:

insert_array = np.array([[1,2,3],[4,5,6]])
# we can insert values into array index 6 - at the end
insert_array = np.insert(insert_array, 6, 10)
# we can also insert at the begining
insert_array = np.insert(insert_array, 0, 100)
insert_array

# In[106]:

# we can fill up the whole column given value
insert_2 = np.arange(0,9).reshape(3,3)
print("original array:")
print(insert_2)

# we can insert 0s in second column
insert_2 = np.insert(insert_2, 1, 0, axis=1)
print("\nafter inserting 0's on the first column:")
print(insert_2)

# In[119]:

# we can also insert list as well
list_array = np.arange(0,9).reshape(3,3)
list_array = np.insert(list_array, [1], [[10],[10],[10]], axis=1)
list_array = np.insert(list_array, [1], 10, axis=0)
list_array

# #### Split array in given index?
# numpy.split(ary, indices_or_sections, axis=0)
#
# Split an array into multiple sub-arrays. Check the docstring for complete information on the various ways it can be used.

# In[142]:

or_array = np.array([[1,2,3],[4,5,6]])
print("Orignal array:\n ",or_array)
#splits arr into 3 sub-arrays
split_array = np.split(or_array, 2)
print("\nwe have our array splitted into two arrays")
split_array

# In[149]:

copy_array = np.arange(16.0).reshape(4, 4)
#splits arr horizontally on the 5th index
print("copy array:\n",copy_array)

# we splits our array into horizontal on the given index
h_split = np.hsplit(copy_array, 2)
h_split

# In[154]:

# we can also split array into vertical on the given index
h_split = np.vsplit(copy_array, 2)
h_split


# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
# As a basic numerical computation :
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import binom
import sys

question = input('Please Enter Question Number: (1/2)')

def Can_Kocagil_21602218_Hw1(question):
    if question == '1' :
        # %%
        print('QUESTION 1 part (a) \n')

        # Let's create the matrix A :
        A = np.array([[1, 0, -1, 2],
                    [2, 1, -1, 5],
                    [3, 3, 0, 9]])

        # Since alpha ve beta are arbitrary scalars:
        alpha, beta = (np.random.randn() , np.random.randn())

        # Hand driven solution to the system of Ax = b, x_n is:
        x_n = np.array([[alpha - 2 * beta],
                    [-alpha - beta],
                    [alpha],
                    [beta]])

        # Verification of the solution x_n to the system A * x_n = 0 :
        print(f"Proof that x_n solves the linear system of Ax = b is \n {A @ x_n} \n")

        Q1_TEST = lambda x_n : np.isclose(np.zeros((3,1)), A @ x_n)

        print(f'Q1 Verification \n {Q1_TEST(x_n)}')

        # %%
        print('QUESTION 1 part (b) \n')

        # Let's create the matrix A :
        A = np.array([[1, 0, -1, 2],
                    [2, 1, -1, 5],
                    [3, 3, 0, 9]])

        # Let's create output vector b :
        b = np.array([[1],
                    [4],
                    [9]])

        # Particular solution to the system A * x_p = b :
        x_p = np.array([[1],
                    [2],
                    [0],
                    [0]])

        # Verification of the solution x_n to the system A * x_p = 0 :
        print(f"Proof that x_p solves the linear system of Ax = b is \n {A @ x_p} \n")

        Q1_TEST = lambda x_p : np.isclose(b, A @ x_p)

        print(f'Q1 Verification \n {Q1_TEST(x_p)}')

        # %%
        print('QUESTION 1 part (c) \n')

        # Let's create the matrix A :
        A = np.array([[1, 0, -1, 2],
                    [2, 1, -1, 5],
                    [3, 3, 0, 9]])

        # Since alpha ve beta are arbitrary scalars:
        alpha, beta = (np.random.randn() , np.random.randn())

        # Hand driven solution to the system of Ax = b, x_general is:
        x_general = np.array([[alpha - 2 * beta + 1],
                            [-alpha - beta + 2],
                            [alpha],
                            [beta]])

        # Verification of the solution x_general to the system A * x_general = b :
        print(f"Proof that x_general solves the linear system of Ax = b is \n {A @ x_general} \n")

        Q1_TEST = lambda x_general : np.isclose(b, A @ x_general)

        print(f'Q1 Verification \n {Q1_TEST(x_general)}')

        # %%
        print('QUESTION 1 part (d) \n')

        # Let's apply SVD on matrix A :
        U, S, V_T = np.linalg.svd(A)

        # Little bit of calculation :
        (m,n) = A.shape
        S_plus = np.zeros((m,n))
        S_plus[:m, :m] = np.diag(np.concatenate((1 / S[0:2], np.array([0]))))

        print(f"Pseudo-inverse of A, A_plus is \n {V_T.T @ S_plus.T @ U.T} ")

        Q1_TEST = lambda S_plus : np.isclose( np.linalg.pinv(A), V_T.T @ S_plus.T @ U.T)

        print(f'Q1 Verification \n {Q1_TEST(S_plus)}')

        # %%
        print('QUESTION 1 part (e) \n')
        #from tabulate import tabulate
        # Our hand-driven alpha and beta values :
        alphas = [1,0,0,0,-1,2]
        betas  = [1,0,.5,2,0,0]

        # Let's see whether our alpha-beta values are correct or not:
        table = [[(s_alpha,s_beta),np.array([[s_alpha - 2 * s_beta + 1],
                                            [-s_alpha - s_beta + 2],
                                            [s_alpha],
                                            [s_beta]]).T,(A @ np.array([[s_alpha - 2 * s_beta + 1],
                                            [-s_alpha - s_beta + 2],
                                            [s_alpha],
                                            [s_beta]])).T] for  s_alpha,s_beta in zip(alphas,betas)]

        #print(tabulate(table,headers = ['Alpha-Beta','Sparsest x',' A dot Sparsest X'],tablefmt = 'fancy_grid'))

        # %%
        print('QUESTION 1 part (f) \n')

        print(f"The least norm solution to the system is \n {np.linalg.pinv(A) @ b}")

                ##question 1 code goes here

    elif question == '2' :
        # %%
        print('QUESTION 2 part (a) \n')

        # Given probability ranges :
        prob_range = np.arange(0, 1.00, 0.001)
        language = [binom.pmf(k = 103, n = 869 , p = prob) for prob in prob_range]
        not_language = [binom.pmf(k = 199, n = 2353, p = prob) for prob in prob_range]

        def plot_likelihood(likelihood : list or np.ndarray,
                            xticks : tuple or np.ndarray = (0, 0.05, 0.1, 0.15, 0.2),
                            xtick1 : np.ndarray = np.arange(0, 201, step=50),
                            color  : str = 'orange',
                            xlim         = None,
                            xlabel : str = 'Probability Range',
                            ylabel : str = 'Likehoods',
                            title  : str = 'Likelihood function of tasks involving language') -> None:

            """
            Given the likelihood array or list of float, plots the likelihood function w.r.t.
            given probability range.

                Parameters:
                    - likelihood (list[float] or np.ndarray) : Likelihood function to be plotted
                    - xticks (tuple[float] or np.ndarray)    : set the current tick locations and labels of the x-axis
                    - color (str)                            : Color of the figure
                    - xlim (int)                             : The limit of the x label
                    - xlabel (str)                           : The text of x label
                    - ylabel (str)                           : The text of y label
                    - title (str) :                          : The title of the figure

                Returns:
                    - None

            """

            plt.figure(figsize = (6,6))
            plt.bar(np.arange(len(likelihood)), likelihood, color = color)

            if xlim is not None:
                plt.xlim(0, xlim)

            plt.xticks(xtick1, xticks )
            plt.xlabel(xlabel)
            plt.ylabel(ylabel)
            plt.title(title)
            plt.show(block=False)

        plot_likelihood(language,
                        xlim = 200)
        plot_likelihood(not_language,
                        color = 'green',
                        title = 'Likelihood function of tasks not involving language',
                        xlim = 200)

        # %%
        print('QUESTION 2 part (b) \n')

        table = [ [task, prob_range[np.argmax(likelihood)], max(likelihood)] for likelihood,task in zip([language,not_language], ['Language Involving Tasks', 'Language Not Involving Tasks'])]

        #print(tabulate(table,headers = ['Tasks','Probability that maximixes','Maximum value'],tablefmt = 'fancy_grid'))
        print(table)

        # %%
        print('QUESTION 2 part (c) \n')

        def bayes_theorem(likelihood : np.ndarray, prior : float) -> np.ndarray:
            """
            Given the likelihood function and prior distribution,
            computes and returns the posterior distribution by Bayes' Rule

                Parameters:
                    - likelihood (np.ndarray) : likelihood function (e.g., language or not_language)
                    - prior (float)           : prior distribution as a probability value

                Returns:
                    - Posterior probability (np.ndarray) with normalization

            """

            # Normalizing all likelihood values
            normalization_constant = np.sum(likelihood * prior)

            # Computing posterior distribution
            posterior = likelihood * prior

            return posterior/normalization_constant

        uniform_prior = 1 / len(prob_range)

        posterior_language = bayes_theorem(np.array(language),uniform_prior)
        plot_likelihood(likelihood = posterior_language,
                        color = 'b',
                        title = 'Posterior distribution for language involving tasks',
                        xlim = 200)

        posterior_not_language = bayes_theorem(np.array(not_language),uniform_prior)
        plot_likelihood(likelihood = posterior_not_language,
                        color = 'purple',
                        title = 'Posterior distribution for not language involving tasks',
                        xlim = 200)

        # %%
        # Calculating CDF of language involving tasks and plottings:
        posterior_language_cdf = [np.sum(posterior_language[:until]) for until in range(1, len(prob_range) + 1)]

        plot_likelihood(likelihood = posterior_language_cdf,
                        xticks     = np.around(np.arange(0, 1.001, 0.1), 2),
                        xtick1     = np.arange(0, 1001, 100),
                        title      = 'Cumulative distribution of tasks involving language',
                        ylabel     = 'Cumulative Distribution Function (CDF)',
                        color      = 'm')

        # Calculating CDF of not language involving tasks and plottings:
        posterior_not_language_cdf = [np.sum(posterior_not_language[:until]) for until in range(1, len(prob_range) + 1)]

        plot_likelihood(likelihood = posterior_not_language_cdf,
                        xticks     = np.around(np.arange(0, 1.001, 0.1), 2),
                        xtick1     = np.arange(0, 1001, 100),
                        title      = 'Cumulative distribution of tasks not involving language',
                        ylabel     = 'Cumulative Distribution Function (CDF)',
                        color      = 'red')

        # %%
        # Efficients calculations of CDF:
        cdf_language = np.empty(len(posterior_language))
        for i in range(len(posterior_language)):
            if i == 0:
                cdf_language[i] = posterior_language[i]
            else:
                cdf_language[i] = cdf_language[i-1] + posterior_language[i]

        plot_likelihood(likelihood = cdf_language,
                        xticks     = np.around(np.arange(0, 1.001, 0.1), 2),
                        xtick1     = np.arange(0, 1001, 100),
                        title      = 'Cumulative distribution of tasks involving language',
                        ylabel     = 'Cumulative Distribution Function (CDF)',
                        color      = 'm')

        # Efficients calculations of CDF:
        posterior_not_language_cdf = np.empty(len(posterior_not_language))
        for i in range(1, len(posterior_not_language)):
            if i == 0:
                posterior_not_language_cdf[i] = posterior_not_language[i]
            else:
                posterior_not_language_cdf[i] = posterior_not_language_cdf[i-1] + posterior_not_language[i]

        plot_likelihood(likelihood = posterior_not_language_cdf,
                        xticks     = np.around(np.arange(0, 1.001, 0.1), 2),
                        xtick1     = np.arange(0, 1001, 100),
                        title      = 'Cumulative distribution of tasks not involving language',
                        ylabel     = 'Cumulative Distribution Function (CDF)',
                        color      = 'g')

        # %%
        lower_bound = 0.025
        upper_bound = 0.975
        flags = [True] * 4

        i = 0
        while any(flags) and i < len(prob_range):

            if cdf_language[i] >= lower_bound and flags[0]:
                lower_confidence_interval_l = prob_range[i]
                flags[0] = False

            if cdf_language[i] >= upper_bound and flags[1]:
                higher_confidence_interval_l = prob_range[i]
                flags[1] = False

            if posterior_not_language_cdf[i] >= lower_bound and flags[2]:
                lower_confidence_interval_nl = prob_range[i]
                flags[2] = False

            if posterior_not_language_cdf[i] >= upper_bound and flags[3]:
                higher_confidence_interval_nl = prob_range[i]
                flags[3] = False

            i += 1

        print(f"Lower 95% confidence for language involving tasks likelihood CDF {lower_confidence_interval_l} ")

        print(f"Higher 95% confidence for language involving tasks likelihood CDF {higher_confidence_interval_l} ")

        print(f"Lower 95% confidence for language not involving tasks likelihood CDF {lower_confidence_interval_nl} ")

        print(f"Higher 95% confidence for language not involving tasks likelihood CDF {higher_confidence_interval_nl} ")

        # %%
        print('QUESTION 2 part (d) \n')
        plt.figure()
        joint = np.outer(posterior_language.T,posterior_not_language)
        plt.imshow(joint)
        plt.colorbar()
        plt.title('The joint posterior distribution')
        plt.xlabel('Language Involving RV (X_l)')
        plt.ylabel('Language Not Involving RV (X_nl)')
        plt.xticks(np.arange(len(posterior_language), step=100),
                np.round(np.arange(0.1,1.1,0.1),3))
        plt.yticks(np.arange(len(posterior_language), step=100),
                np.round(np.arange(0.1,1.1,0.1),3))
        plt.show(block=False)

        # %%
        # computing the P(X_l > X_nl | data) and P(X_nl >= X_l | data)

        assert len(posterior_language) == len(posterior_not_language)

        lower_tri_sum = 0
        upper_and_diag_tri_sum = 0
        for i in range(len(posterior_language)):
            for j in range(len(posterior_not_language)):
                if i > j:
                    lower_tri_sum += joint[i,j]
                else:
                    upper_and_diag_tri_sum += joint[i,j]

        print(f"Sum of entries of lower triangle of joint distribution (i.e., P(X_l > X_nl | data)) = {lower_tri_sum} \n")

        print(f"Sum of entries of upper triangle and diagonal of joint distribution (i.e., P(X_nl >= X_l | data) )  = {upper_and_diag_tri_sum}")

        # %%
        print('QUESTION 2 part (e) \n')
        # Here, let's recall and recompute the conditional probabilities :
        max_prop_l  = prob_range[np.argmax(language)]
        max_prop_nl = prob_range[np.argmax(not_language)]

        # P(Language) = 0.5 is given :
        p_language = .5

        # Here is the Bayes' Rule for inferensing:
        p_language_given_activation = max_prop_l * p_language / ( ( max_prop_l * p_language) + (max_prop_nl * (1-p_language)))

        print(f"P(language|activation) = {p_language_given_activation} ")

    else:
        print('Wrong Number question, please give 1 or 2')

Can_Kocagil_21602218_Hw1(question)


import sympy
import time

## From Bent: 2000_1 Computer Bonus
## Computer Bonus
##
## Find the smallest integer greater than one which has the property that
## the sum of all the integral divisors of its square equals a perfect
## cube. One and N are both divisors of N.
##
## -- Pierre de Fermat (circa 1650)
##
## Smallest solution (other than 1) = 43098
## This is also the only solution below 1e7
##

max_n = 1_000_000
solutions = []

t1=time.time()
for n in range(1,max_n+1):
    x=sympy.factorint(n*n)
    s=1
    for k in x:
        t=1
        for m in range(x[k]):
            t=k*t+1
        s=s*t
    # s = sum of the factors of the square of n
    # Check to see if it is a perfect cube
    c=round(s**(1/3))
    if c*c*c == s:
        print("Solution = ",n,"   Time = ",time.time()-t1)
        solutions.append(n)
t2=time.time()
print("Total elapsed time = ",t2-t1)
print("Largest value tested = ",max_n)
print("Number of solutions = ",len(solutions))
print("Solution set:")
print(solutions)


import matplotlib.pyplot as plt
import numpy as np

u = np.linspace(-1, 1, 200)
v = np.linspace(0, 3, 360)
uu, vv = np.meshgrid(u, v)
z0 = uu + 1j * vv
z = (1j * z0 + 1) / (z0 + 1j)

T = np.arctan2(uu, vv)

plt.figure(figsize=(14, 6))
plt.subplot(1, 2, 1)
plt.scatter(uu, vv, c=T, s=10, lw=0, cmap='hsv')
plt.title('real points')
plt.xlabel('Re(z)')
plt.ylabel('Im(z)')
plt.axis('equal')
plt.grid(True)

plt.subplot(1, 2, 2)
plt.scatter(np.real(z), np.imag(z), c=T, s=10, lw=0, cmap='hsv')
plt.title('poincare disk')
plt.xlabel('Re(z)')
plt.ylabel('Im(z)')
plt.axis('equal')
plt.grid(True)
plt.show()


import math
import sympy
import datetime

class RSA_key_gen:
    exponent_choices = [29, 23, 19, 17, 13, 7, 5, 3]

    n = 0
    d = 0
    e = 0

    test_ints = [0, 1, 2, 4, 3, 6, 7, 9, 16, 23, 512, 1024, 2056, 513, 112, 111, 100, 233]

    def __init__(self, min_prime_size=1, max_prime_size=100000000, *args, **kwargs):
        self.prime1 = sympy.randprime(min_prime_size, max_prime_size)
        self.prime2 = sympy.randprime(min_prime_size, max_prime_size)
        duplicates = 0
        while(self.prime2 == self.prime1):
            self.prime2 = sympy.randprime(min_prime_size, max_prime_size)
            duplicates += 1
            if duplicates > 4:
                print('Range invalid.')
                exit()

    def rsa_pair_is_valid(self):
        valid = True
        for test_int in self.test_ints:
            if test_int < self.n:
                cyper_text = pow(test_int, self.e, mod=self.n)
                plain_text = pow(cyper_text, self.d, mod=self.n)
                if test_int != plain_text:
                    valid = False
                    break
        return valid

    def calculate_d(phi, e):
        multiple = 1
        while (phi * multiple + 1) % e != 0:
            multiple += 1
        return (multiple * phi + 1) / e

    def create_pair(self):
        print(f'For primes: {self.prime1} {self.prime2}')
        self.n = self.prime1 * self.prime2
        phi = (self.prime1 - 1) * (self.prime2 - 1)
        self.e = 3
        for option in self.exponent_choices:
            if option < phi and math.gcd(option, phi) == 1:
                self.e = option
        self.d = RSA_key_gen.calculate_d(phi, self.e)
        print(f'The smallest corresponding RSA key pair is: n={self.n}, e={self.e}, phi={phi}, d={self.d}')
        self.d = int(self.d)
        print(f'Key is valid: {self.rsa_pair_is_valid()}')

    def break_pair(self):
        print(f'For public key: n={self.n} and e={self.e}')
        digits_to_cut = int((math.log10(self.n) + 1) / 2) - 1
        divisor = pow(10, digits_to_cut)
        max_min = int(self.n / divisor) + 1
        if max_min % 2 == 0:
            max_min -= 1
        current_guess = max_min

        start_search = datetime.datetime.now()
        prime_numbers = sympy.primerange(max_min)
        for prime in prime_numbers:
            if pow(self.n, 1, mod=prime) == 0:
                current_guess = prime
                break
        if current_guess == max_min:
            print('Failed to find base primes.')
            exit()
        print(f'Broke the primes in: {datetime.datetime.now() - start_search}')

        other_prime = self.n / current_guess
        phi = (current_guess - 1) * (other_prime - 1)
        private_key = RSA_key_gen.calculate_d(phi, self.e)
        print(f'The private key is: {private_key}. With base primes: {current_guess} and {other_prime}.')

# if len(sys.argv) < 2:
#     print('Supply at minimum an action argument.')
#     print('Options are "create", "break d e", "create_and_break".')
#     exit()
# action = sys.argv[1]

# key_gen = RSA_key_gen()

# if action == 'create':
#     print('Creating new RSA pair')
#     key_gen.create_pair()
# elif action == 'break':
#     print('Breaking inputted RSA pair')
#     key_gen.n = int(sys.argv[2])
#     key_gen.e = int(sys.argv[3])
#     key_gen.break_pair()
# elif action == 'create_and_break':
#     print('Creating and breaking RSA pair')
#     key_gen.create_pair()
#     key_gen.break_pair()
# else:
#     print('Invalid action command.')
#     print('Options are "create", "break d e", "create_and_break".')
#     exit()


import numpy as np

def mse_loss(y_true, y_pred):
  # y_true and y_pred are numpy arrays of the same length.
  return ((y_true - y_pred) ** 2).mean()

y_true = np.array([1, 0, 0, 1])
y_pred = np.array([0, 0, 0, 0])

print(mse_loss(y_true, y_pred)) # 0.5


import numpy as np
from coptim.function import Function

class Brown(Function):

    def eval(self, x):
        assert len(x) == 2, '2 dimensional input only.'
        return (np.power(x[0] - 1e6, 2) +
                np.power((x[1] - (2 * 1e-6)), 2) +
                np.power((x[0] * x[1] - 2), 2))

    def gradient(self, x):
        assert len(x) == 2, '2 dimensional input only.'
        return np.array([
            2 * x[0] * (x[1] ** 2 + 1) - 4 * (x[1] + 500000),
            2 * (x[0] * (x[0] * x[1] - 2) + x[1] - (1 / 500000))
        ])

    def hessian(self, x):
        assert len(x) == 2, '2 dimensional input only.'
        dfdx1 = 2 + (2 * x[1] ** 2)
        dfdx1dx2 = 4 * x[0] * x[1] - 4
        dfdx2dx1 = 4 * x[0] * x[1] - 4
        dfdx2 = 2 + (2 * x[0] ** 2)

        return np.array([[dfdx1, dfdx1dx2], [dfdx2dx1, dfdx2]])


"""This module attempts to get two pieces of data to be as similar as possible
using only orthogonal transformations. Many analyses are unique only up to
orthonormal transformations

This module is specifically referring to matrices of shape
(in_features, out_features).

Restated, the goal is to minimize the frobenius distance between two matrices
using only an orthonormal matrix.

Restated, let A and B be matrices. First find

 R = argmin | NA - B |F
       N
    where N is orthonormal

And the result is (NA, B)

This problem is known as the Orthogonal Procrustes Problem and has a simple
solution using SVD: https://en.wikipedia.org/wiki/Orthogonal_Procrustes_problem

It's straightforward to convert to minimizing (A - BN) by noting that forbenius
norms are invariant to transposes and multiplications by units (+/- 1)
"""

import numpy as np
import scipy.linalg
import pytypeutils as tus
import pca3dvis.snapshot as snapshot

def match(a: np.ndarray, b: np.ndarray) -> np.ndarray:
    """Finds the matrix R that minimizes the frobenius norm of RA - B, where
    R is orthonormal.

    Args:
        a (np.ndarray[samples, features]): the first matrix to match
        b (np.ndarray[samples, features]): the second matrix to match

    Returns:
        np.ndarray: the orthonormal matching matrix R
    """
    tus.check_ndarrays(
        a=(a, ('samples', 'features'), ('float32', 'float64')),
        b=(b, (('samples', a.shape[0]), ('features', a.shape[1])), a.dtype)
    )
    m = b @ a.T
    u, _, vh = scipy.linalg.svd(m)
    return np.real(u @ vh)

def match_snaps(
        reference: snapshot.ProjectedSnapshot,
        tomatch: snapshot.ProjectedSnapshot) -> snapshot.ProjectedSnapshot:
    """Returns a new snapshot that is a transformation the tomatch snapshot
    to match the reference snapshot. Neither argument is modified.

    Reason why this works:

    Let A be reference projected samples.
    Let B be tomatch projected samples.

    Then |A - BN| = |(A-BN)'| = |A' - N'B'| = |N'B' - A'|
    """

    transform = match(tomatch.projected_samples.T, reference.projected_samples.T)
    return snapshot.ProjectedSnapshot(
        tomatch.projection_vectors @ transform.T,
        tomatch.projected_samples @ transform.T,
        tomatch.projected_sample_labels
    )


import numpy as np
import matplotlib.pyplot as plt

import jetFunctions as jet

dataPath = '11-jet/data/'
plotsPath = '11-jet/plots/'

########################################
#   Pressure calibration
########################################

p00, steps, count = jet.read(dataPath + 'calibration/00 Pa.txt')
p70, steps, count = jet.read(dataPath + 'calibration/70 Pa.txt')

pressure = [0, 70] # Pa
adc = [int(p00.mean()), int(p70.mean())]

linearFit = np.polyfit(adc, pressure, 1)

adcFit = np.linspace(int(p00.mean()), int(p70.mean()), 100)
pressureFit = np.polyval(linearFit, adcFit)

# Plot

plt.figure('Калибровка давления', figsize=(8, 6), dpi=200)

plt.title('Калибровочный график\nзависимости показаний АЦП от давления')
plt.xlabel('Далвение [Па]')
plt.ylabel('Отсчёты АЦП')

plt.plot(pressure, adc, '*', label='Измерения')
plt.plot(pressureFit, adcFit, label='P = {:.3f} * N - {:.2f} [Па]'.format(linearFit[0], -linearFit[1]))
plt.legend()

plt.grid(which='major')
plt.grid(which='minor', linestyle='--')
plt.minorticks_on()

plt.savefig(plotsPath + 'pressure-calibration.png')

########################################
#   Distance calibration
########################################

xTotalDistance = 50 / 1000 # m
xTotalSteps = 900 # steps
xStep = xTotalDistance / xTotalSteps # m / step

step = [0, xTotalSteps]
distance = np.array([0, xTotalDistance])

stepsLinearFit = np.polyfit(step, distance, 1)

stepFit = np.linspace(0, xTotalSteps, 100)
distanceFit = np.polyval(stepsLinearFit, stepFit)

# Plot

plt.figure('Калибровка расстояния', figsize=(8, 6), dpi=200)

plt.title('Калибровочный график\nзависимости перемещения трубки Пито от шага двигателя')
plt.xlabel('Количество шагов')
plt.ylabel('Перемещение трубки Пито [см]')

plt.plot(step, distance * 100, '*', label='Измерения')
plt.plot(stepFit, distanceFit * 100, label='X = {:.1e} * step [м]'.format(xStep))
plt.legend()

plt.grid(which='major')
plt.grid(which='minor', linestyle='--')
plt.minorticks_on()

plt.savefig(plotsPath + 'distance-calibration.png')

########################################
#   Processing
########################################

measuresDirectory = '100 measures/'

airDensity = 1.2 # kg / m^3

def calculateVelocity(filename, xCorrection):
    data, steps, count = jet.read(filename)

    p = np.polyval(linearFit, data) # Pa
    p[p < 3] = 0
    u = np.sqrt(2 * abs(p) / airDensity) # m / s

    dx = xStep * steps
    x = np.linspace(0, count * dx, count) - xCorrection / 1000

    return x, u, dx

def calculateOutgo(x, u, dx):
    dq = 2 * np.pi * airDensity * u * abs(x) * dx # kg / s
    q = sum(dq) / 2 # kg / s

    return q

x00, u00, dx = calculateVelocity(dataPath + measuresDirectory + '00 mm.txt', 27.9)
x10, u10, dx = calculateVelocity(dataPath + measuresDirectory + '10 mm.txt', 27.9)
x20, u20, dx = calculateVelocity(dataPath + measuresDirectory + '20 mm.txt', 27.9)
x30, u30, dx = calculateVelocity(dataPath + measuresDirectory + '30 mm.txt', 27.4)
x40, u40, dx = calculateVelocity(dataPath + measuresDirectory + '40 mm.txt', 28.5)
x50, u50, dx = calculateVelocity(dataPath + measuresDirectory + '50 mm.txt', 26.9)
x60, u60, dx = calculateVelocity(dataPath + measuresDirectory + '60 mm.txt', 26.5)
x70, u70, dx = calculateVelocity(dataPath + measuresDirectory + '70 mm.txt', 27.5)
x80, u80, dx = calculateVelocity(dataPath + measuresDirectory + '80 mm.txt', 28.9)
x90, u90, dx = calculateVelocity(dataPath + measuresDirectory + '90 mm.txt', 31.2)

q00 = calculateOutgo(x00, u00, dx)
q10 = calculateOutgo(x10, u10, dx)
q20 = calculateOutgo(x20, u20, dx)
q30 = calculateOutgo(x30, u30, dx)
q40 = calculateOutgo(x40, u40, dx)
q50 = calculateOutgo(x50, u50, dx)
q60 = calculateOutgo(x60, u60, dx)
q70 = calculateOutgo(x70, u70, dx)
q80 = calculateOutgo(x80, u80, dx)
q90 = calculateOutgo(x90, u80, dx)

# Plot

plt.figure('Скорость и расход', figsize=(10, 7), dpi=200)

plt.title('Скорость потока воздуха\nв сечении затопленной струи')
plt.xlabel('Положение трубки Пито относительно центра струи [мм]')
plt.ylabel('Скоровть воздуха [м/с]')

plt.plot(x00 * 1000, u00, label='Q (00 мм) = {:.2f} [г/с]'.format(q00 * 1000))
plt.plot(x10 * 1000, u10, label='Q (10 мм) = {:.2f} [г/с]'.format(q10 * 1000))
plt.plot(x20 * 1000, u20, label='Q (20 мм) = {:.2f} [г/с]'.format(q20 * 1000))
plt.plot(x30 * 1000, u30, label='Q (30 мм) = {:.2f} [г/с]'.format(q30 * 1000))
plt.plot(x40 * 1000, u40, label='Q (40 мм) = {:.2f} [г/с]'.format(q40 * 1000))
plt.plot(x50 * 1000, u50, label='Q (50 мм) = {:.2f} [г/с]'.format(q50 * 1000))
plt.plot(x60 * 1000, u60, label='Q (60 мм) = {:.2f} [г/с]'.format(q60 * 1000))
plt.plot(x70 * 1000, u70, label='Q (70 мм) = {:.2f} [г/с]'.format(q70 * 1000))
plt.plot(x80 * 1000, u80, label='Q (80 мм) = {:.2f} [г/с]'.format(q80 * 1000))
plt.plot(x90 * 1000, u90, label='Q (90 мм) = {:.2f} [г/с]'.format(q90 * 1000))
plt.legend()

plt.grid(which='major')
plt.grid(which='minor', linestyle='--')
plt.minorticks_on()

plt.savefig(plotsPath + 'velocity-outgo.png')


import pandas as pd
import altair as alt
from scipy.signal import savgol_filter
from math import sqrt
def averageUncertainty(X,ΔX):
    n = len(X)
    Average = sum(X)/n
    Uncertainty = sqrt(sum([(Xk-Average)**2 for Xk in X])/n/(n-1) +  ΔX**2/3)
    return (Average,Uncertainty)

def averageUncertaintyPrint(X,ΔX):
    print("The average is %s, and the unvertainty is %s"%averageUncertainty(X,ΔX))

def linearRegression(X,Y):
    n = len(X)
    x = sum(X) / n
    y = sum(Y) / n
    Sxx = sum([(xi - x)**2 for xi in X])
    Sxy = sum([(xi - x)*(yi - y) for (xi,yi) in zip(X,Y)])
    Syy = sum([(yi - y)**2 for yi in Y])
    k = Sxy/Sxx #斜率k
    b = y - k * x #截距b
    Uk = sqrt((Syy/Sxx - k**2)/(n-2))
    Ub = Uk*sqrt(sum([xi**2 for xi in X])/n)
    r = Sxy/sqrt(Sxx*Syy)#相关系数r
    return (k,b,Uk,Ub,r)
def linearRegressionPrint(X,Y):
    print("k = %s, b = %s, Uk = %s, Ub = %s, r = %s"%linearRegression(X,Y))

def pointGraph(X,Y,Xname="X",Yname="Y",color="#000000"):
    df = pd.DataFrame({
    Xname:X,
    Yname:Y,
    })
    Graph = alt.Chart(df).mark_circle(color=color).encode(
        alt.X(Xname),
        alt.Y(Yname),
        tooltip=[Xname,Yname],
    ).interactive()
    return Graph
def lineGraph(X,Y,Xname="X",Yname="Y",color="#66ccff"):
    df = pd.DataFrame({
        Xname:X,
        Yname:Y,
    })
    Graph = alt.Chart(df).mark_line(color=color).encode(
        alt.X(Xname),
        alt.Y(Yname),
        tooltip = [Xname,Yname]
    ).interactive()
    return Graph
def curveGraph(X,Y,Xname="X",Yname="Y",color="#66ccff",part=3,polynomialOrder=2):
    newY = savgol_filter(Y, int(len(Y)/part), polynomialOrder)
    return lineGraph(X,newY,Xname=Xname,Yname=Yname,color=color)
def linearRegressionGraph(X,Y,Xname="X",Yname="Y",color="#66ccff"):
    (k,b,Uk,Ub,r)=linearRegression(X,Y)
    f = lambda x:k*x+b
    X=sorted(X)
    left = X[0] + X[0] - X[1]
    right = X[-1] + X[-1] - X[-2]
    newX = [left,right]
    newY = [f(left),f(right)]
    return lineGraph(newX,newY,Xname=Xname,Yname=Yname,color=color)

aU = averageUncertainty
aUP = averageUncertaintyPrint
lR = linearRegression
lRP = linearRegressionPrint
pG = pointGraph
lG = lineGraph
cG = curveGraph
lRG = linearRegressionGraph


# Code by Desh Iyer

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

# PROBLEM STATEMENT

# 1) Generate a random sample with mean = 5, std. dev. = 2. 2) Plot the distribution. 3) Give the summary statistics

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

# TODO

# [X] - Generate a random sample with mean = 5, std. dev. = 2.
# [X] - Plot the distribution.
# [X] - Give the summary statistics

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

# SOLUTION

# Importing libraries
import numpy as np
import matplotlib.pyplot as plt

# Accept number of elements to generate thru' user input
numberSample = int(input("Number of samples: "))

# Generate the array using the numpy.random.normal(mean, std, numberOfElts) method
sampleArray = np.random.normal(5, 2, numberSample)

# Calculate mean and std. deviation of the generated array
sampleArrayMean = np.mean(sampleArray)
sampleArrayStd = np.std(sampleArray)
sampleArrayVar = np.var(sampleArray)

# Give the summary statistics
print("\nGenerated Sample List with {} elements:\n\n{}\n\n------SUMMARY------\n\nCalculated Mean = {:.3f}\nCalculated Standard Deviation = {:.3f}\nCalculated Variance = {:.3f}\n".format(
    numberSample, sampleArray, sampleArrayMean, sampleArrayStd, sampleArrayVar
))

# Plotting the graph
# Setting a grid
plt.grid()

# Setting graph title
plt.title("Normal distribution w/ Mean: 5 & Std. Deviation: 2")

# Setting axes labels
plt.xlabel('x')
plt.ylabel('Normal Distribution')

# Plotting and displaying graph
plt.hist(sampleArray)
plt.show()


from UQpy.stochastic_process import SpectralRepresentation
import numpy as np

n_sim = 10  # Number of samples
n = 2  # Number of Dimensions
m = 3  # Number of Variables

# Time
T = 10  # Simulation Time
dt = 0.1
nt = int(T / dt) + 1
t = np.linspace(0, T, nt)

# Frequency
nw = 100
W = np.array([1.5, 2.5])
dw = W / (nw - 1)

x_list = [np.linspace(dw[i], W[i], nw) for i in range(n)]
xy_list = np.array(np.meshgrid(*x_list, indexing='ij'))

S_11 = 125 / 4 * np.linalg.norm(xy_list, axis=0) ** 2 * np.exp(-5 * np.linalg.norm(xy_list, axis=0))
S_22 = 125 / 4 * np.linalg.norm(xy_list, axis=0) ** 2 * np.exp(-3 * np.linalg.norm(xy_list, axis=0))
S_33 = 125 / 4 * np.linalg.norm(xy_list, axis=0) ** 2 * np.exp(-7 * np.linalg.norm(xy_list, axis=0))

g_12 = np.exp(-0.1757 * np.linalg.norm(xy_list, axis=0))
g_13 = np.exp(-3.478 * np.linalg.norm(xy_list, axis=0))
g_23 = np.exp(-3.392 * np.linalg.norm(xy_list, axis=0))

S_list = np.array([S_11, S_22, S_33])
g_list = np.array([g_12, g_13, g_23])

# Assembly of S_jk
S_sqrt = np.sqrt(S_list)
S_jk = np.einsum('i...,j...->ij...', S_sqrt, S_sqrt)
# Assembly of g_jk
g_jk = np.zeros_like(S_jk)
counter = 0
for i in range(m):
    for j in range(i + 1, m):
        g_jk[i, j] = g_list[counter]
        counter = counter + 1
g_jk = np.einsum('ij...->ji...', g_jk) + g_jk

for i in range(m):
    g_jk[i, i] = np.ones_like(S_jk[0, 0])
S_nd_mv = S_jk * g_jk

SRM_object = SpectralRepresentation(n_sim, S_nd_mv, [dt, dt], dw, [nt, nt], [nw, nw], random_state=128)
samples_nd_mv = SRM_object.samples

def test_samples_nd_mv_shape():
    assert samples_nd_mv.shape == (n_sim, m, nt, nt)

def test_samples_nd_mv_values():
    assert np.isclose(samples_nd_mv[3, 1, 31, 79], 0.7922504882569233)


# skl_LinearR_v1a.py
# Demo of linear regression by scikit-learn
# Copyright 2021 YouCans, XUPT
# Crated：2021-05-12
#  -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error, median_absolute_error

# 生成测试数据:
nSample = 100
x = np.linspace(0, 10, nSample)  # 起点为 0，终点为 10，均分为 nSample个点
e = np.random.normal(size=len(x))  # 正态分布随机数
y = 2.36 + 1.58 * x + e  # y = b0 + b1*x1

# 按照模型要求进行数据转换：输入是 array类型的 n*m 矩阵，输出是 array类型的 n*1 数组
x = x.reshape(-1, 1)  # 输入转换为 n行 1列（多元回归则为多列）的二维数组
y = y.reshape(-1, 1)  # 输出转换为 n行1列的二维数组
# print(x.shape,y.shape)

# 一元线性回归：最小二乘法(OLS)
modelRegL = LinearRegression()  # 创建线性回归模型
modelRegL.fit(x, y)  # 模型训练：数据拟合
yFit = modelRegL.predict(x)  # 用回归模型来预测输出

# 输出回归结果 XUPT
print('回归截距: w0={}'.format(modelRegL.intercept_))  # w0: 截距
print('回归系数: w1={}'.format(modelRegL.coef_))  # w1,..wm: 回归系数

# 回归模型的评价指标 YouCans
print('R2 确定系数：{:.4f}'.format(modelRegL.score(x, y)))  # R2 判定系数
print('R2 确定系数：{:.4f}'.format(r2_score(x, y)))  # R2 判定系数
print('均方误差：{:.4f}'.format(mean_squared_error(y, yFit)))  # MSE 均方误差
print('平均绝对值误差：{:.4f}'.format(mean_absolute_error(y, yFit)))  # MAE 平均绝对误差
print('中位绝对值误差：{:.4f}'.format(median_absolute_error(y, yFit)))  # 中值绝对误差

# 绘图：原始数据点，拟合曲线
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y, 'o', label="data")  # 原始数据
ax.plot(x, yFit, 'r-', label="OLS")  # 拟合数据

ax.legend(loc='best')  # 显示图例
plt.title('Linear regression by sklearn (Youcans)')
plt.show()  # YouCans, XUPT
# === 关注 Youcans，分享更多原创系列 https://www.cnblogs.com/youcans/ ===


import numpy as np

def pol2cart(angle, r):
    """
    Conversion from polar coordinates to cartesians
    :param angle:  Degrees of the speaker from [1, 0] vector in degree
    :param r: radius of the arena
    :return: [x, y] of the speaker, in cm relative to the center of the arena = [0, 0]
    """

    theta = np.deg2rad(angle)
    x = r * np.cos(theta)
    y = r * np.sin(theta)
    return x, y

def calc_d_angle(body_angle, head_angle):
    """
    Function that computes the relative angle between the head and the body, in range [-180, 180]
    :param body_angle: (N x 1 ndarray) - Angles in [0, 360]
    :param head_angle:  (N x 1 ndarray) - Angles in [0, 360]
    :return: dAngle - (N x 1 ndarray) - Relative angle in degrees, in range [-180, 180].
    """
    dAngle = np.mod(head_angle - body_angle, 360)
    if np.isscalar(dAngle):
        if np.abs(dAngle) > 180:
            dAngle -= 360
    else:
        rescale_at_inds = np.abs(dAngle) > 180
        dAngle[rescale_at_inds] -= 360
    return dAngle

def cart2pol(loc):
    """
    Converts the cartesian coordinates into polar ones
    :param loc:
    :return:
        r - distance from [0, 0]
        deg - angle to the location of the rat from the vector [1, 0], in degrees
    """

    theta = np.arctan2(loc[1], loc[0])
    rho = np.hypot(loc[0], loc[1])
    ang_wrapped = np.round(np.mod(np.rad2deg(theta), 360), 7)
    # Round -> Fix numerical instabilities
    # mod() -> wrap to 360
    return rho, ang_wrapped

def average_angle(direc_mat):
    """
    Averages the angle vectors along samples. The input matrix (NxM) is parsed as M vectors,
    each with N samples. Each M-tuple is averages into a single angle, and a vector of size
    N is returned.
    :param direc_mat: (NxM array) - M direction vectors of N samples each, [0, 360]. Averaging M samples.
    :return: (Nx1 array) - The average direction vector
    """
    n_direcs, n_vecs = direc_mat.shape
    xs = np.zeros(direc_mat[:, 0].shape)
    ys = np.zeros(direc_mat[:, 0].shape)
    rs = np.ones(direc_mat[:, 0].shape)

    for i in range(n_vecs):
        loc = pol2cart(direc_mat[:, i], rs)
        xs += loc[0]
        ys += loc[1]

    xs /= n_vecs
    ys /= n_vecs
    r, av_direcs = cart2pol((xs, ys))
    return av_direcs

def smooth_angles(direcs, kernel_size):
    """
    Smooth angle vector, with consideration of angle circularity: 1 deg is close to 359 deg
    :param direcs: (Nx1 vector) - Direction vector, [0, 360]
    :param kernel_size: (scalar) - The size of the smoothing kernel to be used. Should be even.
    :return: (1xN vector) - Smoothed direction vector
    """
    rs = np.ones(direcs.shape)
    loc = pol2cart(direcs, rs)
    [r, angle] = cart2pol([smooth(loc[0], kernel_size), smooth(loc[1], kernel_size)])
    return angle

def smooth(vec, window):
    """
    Function that smooths the input vector by a sliding window - analog to matlab's smooth().
    :param vec: (1xN vector) - The input signal
    :param window: (scalar) - The size of the smoothing kernel to be used. Should be even.
    :return: (1xN vector) - Smoothed signal
    """

    if (window % 2) == 0:
        window += 1
    vec_flat = vec.flatten()
    filt_sig = np.convolve(vec_flat, np.ones(window, dtype=int), 'valid') / window
    r = np.arange(1, window - 1, 2)
    ramp_up = np.cumsum(vec_flat[:window - 1])[::2] / r
    ramp_down = (np.cumsum(vec_flat[:-window:-1])[::2] / r)[::-1]
    return np.concatenate((ramp_up, filt_sig, ramp_down))

if __name__ == '__main__':
    pass

    # === Test angle averaging ===
    # ang = (np.random.randn(1000, 1) + 2) % 360
    # angs_smoothed = smooth_angles(ang, 9)

    # === Test angle averaging ===
    # direcs = np.arange(8)*45
    # n_vects = 1000
    # direc_mat = np.zeros([8, n_vects])
    # for i in range(n_vects):
    #     direc_mat[:, [i]] = np.reshape(direcs, [8, 1]) + np.random.randn(8, 1)
    # av_direcs = average_angle(direc_mat)
    # print(np.round(av_direcs, 2))

    # === Test direction conversion - vectors ===
    # direcs = np.arange(8)*45
    # rs = np.zeros(8)+1
    #
    # loc = pol2cart(direcs, rs)
    # [r, angle] = cart2pol(loc)

    # === Test direction conversion - scalars ===
    # for i in range(8):
    #     loc = pol2cart(45*i, 1)
    #     [r, angle] = cart2pol(loc)
    #     print(str(45*i) + ' ' + str(1) + ' -> ' + str(angle) + ' ' + str(r))


import math
from typing import Union
import numpy as np
import torch

def fourier_model_mat(datetimes: np.ndarray,
                      K: int,
                      period: Union[np.timedelta64, str],
                      output_fmt: str = 'float64') -> np.ndarray:
    """
    :param datetimes: An array of datetimes.
    :param K: The expansion integer.
    :param period: Either a np.timedelta64, or one of {'weekly','yearly','daily'}
    :param start_datetime: A np.datetime64 on which to consider the season-start; useful for aligning (e.g) weekly
    seasons to start on Monday, or daily seasons to start on a particular hour. Default is first monday after epoch.
    :param output_fmt: A numpy dtype, or 'dataframe' to output a dataframe.
    :return: A numpy array (or dataframe) with the expanded fourier series.
    """
    # parse period:
    name = 'fourier'
    if isinstance(period, str):
        name = period
        if period == 'weekly':
            period = np.timedelta64(7, 'D')
        elif period == 'yearly':
            period = np.timedelta64(int(365.25 * 24), 'h')
        elif period == 'daily':
            period = np.timedelta64(24, 'h')
        else:
            raise ValueError("Unrecognized `period`.")

    if not isinstance(datetimes, np.ndarray) and isinstance(getattr(datetimes, 'values', None), np.ndarray):
        datetimes = datetimes.values
    period_int = int(period / np.timedelta64(1, 'ns'))
    time_int = (datetimes.astype("datetime64[ns]") - np.datetime64(0, 'ns')).astype('int64')

    output_dataframe = (output_fmt.lower() == 'dataframe')
    if output_dataframe:
        output_fmt = 'float64'

    # fourier matrix:
    out_shape = tuple(datetimes.shape) + (K * 2,)
    out = np.empty(out_shape, dtype=output_fmt)
    columns = []
    for idx in range(K):
        k = idx + 1
        for is_cos in range(2):
            val = 2. * np.pi * k * time_int / period_int
            out[..., idx * 2 + is_cos] = np.sin(val) if is_cos == 0 else np.cos(val)
            columns.append(f"{name}_K{k}_{'cos' if is_cos else 'sin'}")

    if output_dataframe:
        if len(out_shape) > 2:
            raise ValueError("Cannot output dataframe when input is 2+D array.")
        from pandas import DataFrame
        out = DataFrame(out, columns=columns)

    return out

def fourier_tensor(time: torch.Tensor, seasonal_period: float, K: int) -> torch.Tensor:
    """
    Given an N-dimensional tensor, create an N+2 dimensional tensor with the 2nd to last dimension corresponding to the
    Ks and the last dimension corresponding to sin/cos.
    """
    out = torch.empty(time.shape + (K, 2))
    for idx in range(K):
        k = idx + 1
        for sincos in range(2):
            val = 2. * math.pi * k * time / seasonal_period
            out[..., idx, sincos] = torch.sin(val) if sincos == 0 else torch.cos(val)
    return out


import math
from typing import Any, Optional, Tuple

import numpy as np
from numpy import ndarray

def cylinder_area(r: float, h: float) -> float:
    """Obliczenie pola powierzchni walca.
    Szczegółowy opis w zadaniu 1.

    Parameters:
    r (float): promień podstawy walca
    h (float): wysokosć walca

    Returns:
    float: pole powierzchni walca
    """
    nan = float('nan')
    if r > 0 and h > 0:
        p = 2 * math.pi * r * r + 2 * math.pi * r * h
        return p
    else:
        return nan

def fib(n: int) -> np.ndarray or None:
    """Obliczenie pierwszych n wyrazów ciągu Fibonnaciego.
    Szczegółowy opis w zadaniu 3.

    Parameters:
    n (int): liczba określająca ilość wyrazów ciągu do obliczenia

    Returns:
    np.ndarray: wektor n pierwszych wyrazów ciągu Fibonnaciego.
    """
    if type(n) is int:
        vector_of_fib_numbers = np.empty(0, int)
        a_1 = 1
        a_2 = 1
        a_wyn = 0

        if n > 1:
            vector_of_fib_numbers = np.append(vector_of_fib_numbers, [a_1, a_2])
            for i in range(1, n):
                a_wyn = a_2 + a_1

                a_1 = a_2
                a_2 = a_wyn

                vector_of_fib_numbers = np.append(vector_of_fib_numbers, a_2)

            return vector_of_fib_numbers
        elif n == 1:
            vector_of_fib_numbers = np.append(vector_of_fib_numbers, a_1)
            return vector_of_fib_numbers
        else:
            return None

    else:
        return None

def matrix_calculations(a: float) -> Tuple[Any]:
    """Funkcja zwraca wartości obliczeń na macierzy stworzonej
    na podstawie parametru a.
    Szczegółowy opis w zadaniu 4.

    Parameters:
    a (float): wartość liczbowa

    Returns:
    touple: krotka zawierająca wyniki obliczeń
    (Minv, Mt, Mdet) - opis parametrów w zadaniu 4.
    """
    matrix = np.array([[a, 1, -a],
                       [0, 1, 1],
                       [-a, a, 1]])
    matrix_det = np.linalg.det(matrix)
    matrix_transponsed = np.transpose(matrix)

    if matrix_det != 0:
        matrix_inv = np.linalg.inv(matrix)
        t = matrix_inv, matrix_transponsed, matrix_det
    else:
        t = float('nan'), matrix_transponsed, matrix_det

    print(t)
    return t

def custom_matrix(m: int, n: int) -> Optional[ndarray]:
    """Funkcja zwraca macierz o wymiarze mxn zgodnie
    z opisem zadania 7.

    Parameters:
    m (int): ilość wierszy macierzy
    n (int): ilość kolumn macierzy

    Returns:
    np.ndarray: macierz zgodna z opisem z zadania 7.
    """
    if m > 0 and n > 0 and type(m) is int and type(n) is int:
        matrix = np.zeros((m, n))
        for i in range(m):
            for j in range(n):
                if i > j:
                    matrix[i, j] = i
                else:
                    matrix[i, j] = j

        return matrix
    else:
        return None

Metody numeryczne 2021/Laboratorium 1/main.py


import numpy as np

def transiteCartesianToPolar(vector):
    return np.arctan2(vector[1], vector[0])

def transitePolarToCartesian(angle):
    return np.array([np.cos(angle), np.sin(angle)])

def computeAngleBetweenVectors(vector1, vector2):
    vectoriseInnerProduct = np.dot(vector1, vector2.T)
    if np.ndim(vectoriseInnerProduct) > 0:
        innerProduct = vectoriseInnerProduct.diagonal()
    else:
        innerProduct = vectoriseInnerProduct
    angle = np.arccos(innerProduct/(computeVectorNorm(vector1) * computeVectorNorm(vector2)))
    return angle

def computeVectorNorm(vector):
    return np.power(np.power(vector, 2).sum(axis = 0), 0.5)

def getSymmetricVector(symmetricAxis, originalVector):
    orthogonalVector = symmetricAxis.dot(originalVector) * symmetricAxis / np.power(computeVectorNorm(symmetricAxis),2) - originalVector
    symmetricVector = originalVector + 2*orthogonalVector
    return symmetricVector

def calculateCrossEntropy(prediction, target, episilon = 1e-12):
    ce = -1 * sum([target[index] * np.log(prediction[index]+episilon) for index in range(len(prediction))])
    return ce


import numpy as np
from sklearn.datasets import load_iris
from scipy.stats import mode
from sklearn.metrics import accuracy_score

def eucledianDist(p1,p2):
    dist = np.sqrt(np.sum((p1-p2)**2))
    return dist

def kNearestNeighbour(x_train, y_train, x_test, k):
    op_labels = []

    #Loop through the Datapoints to be classified
    for item in x_test:

        #Array to store distances
        point_dist = []

        #Loop through each training Data
        for j in range(len(x_train)):
            dist = eucledianDist(np.array(x_train[j]), item)
            point_dist.append(dist)
        point_dist = np.array(point_dist)

        dist = np.argsort(point_dist)[:k]

        labels = y_train[dist]

        lab = mode(labels)
        lab = lab.mode[0]
        op_labels.append(lab)

    return op_labels

iris = load_iris()

X = iris.data
Y = iris.target

accuracy = 0
test = 40
k = 8
for i in range(test):

    #Creating the training Data
    train_idx = np.random.randint(0,150,150)
    X_train = X[train_idx]
    y_train = Y[train_idx]

    #Creating the testing Data
    test_idx = np.random.randint(0,150,10)
    X_test = X[test_idx]
    y_test = Y[test_idx]

    y_pred = kNearestNeighbour(X_train, y_train, X_test, k)

    accuracy += accuracy_score(y_test, y_pred)

accuracy_result = accuracy / test
print("Unweighted kNearestNeighbour")
print("k = " + str(k))
print("Testruns: " + str(test))
print("Accuracy: " + str(accuracy_result))