I coded a function for Simpson's Rule of numerical integration. For values of n more than or equal to 34, the function returns 0.
Here, n is the number of intervals, a is the start point, and b is the end point.
import math
def simpsons(f, a,b,n):
x = []
h = (b-a)/n
for i in range(n+1):
x.append(a+i*h)
I=0
for i in range(1,(n/2)+1):
I+=f(x[2*i-2])+4*f(x[2*i-1])+f(x[2*i])
return I*(h/3)
def func(x):
return (x**(3/2))/(math.cosh(x))
x = []
print(simpsons(func,0,100,34))
I am not sure why this is happening. I also coded a function for the Trapezoidal Method and that does not return 0 even when n = 50. What is going on here?
Wikipedia has the code for Simpson's rule in Python :
from __future__ import division # Python 2 compatibility
import math
def simpson(f, a, b, n):
"""Approximates the definite integral of f from a to b by the
composite Simpson's rule, using n subintervals (with n even)"""
if n % 2:
raise ValueError("n must be even (received n=%d)" % n)
h = (b - a) / n
s = f(a) + f(b)
for i in range(1, n, 2):
s += 4 * f(a + i * h)
for i in range(2, n-1, 2):
s += 2 * f(a + i * h)
return s * h / 3
def func(x):
return (x**(3/2))/(math.cosh(x))
Related
Am trying to write code for an equation that includes complex number, and put it into a function for simpsons rule.
import numpy as np
import cmath as cmp
import matplotlib.pyplot as plt
wavelength = 0.000001 #meters
Apw = 0.00002 # meters Apw taken as apeture width
z = 0.02 # meters
N = 100
permittivity = 0.00000000000885418783
c = 299792458 # m/s
k = (2*cmp.pi)/wavelength
j = 0 + 1j
n = 100
x = np.linspace(-0.005, 0.005, n, 1.1)
def simps (N, k, Apw, x):
S = 0
h = Apw / N
for i in range(0, N + 1):
for xprime in range(0, N+1):
xprime = Apw*xprime/N
f = cmp.exp(((j*k)/(2*z))*(x-xprime)**2)
if (i != 0) and (i != n):
f *= (2 + (2 * (i % 2)))
S = h/3 * np.sum(f[0:-1:2] + 4*f[1::2] + f[2::2])
return S
x = np.linspace(-0.005, 0.005, n, 1.1)
I = np.zeros([n])
for i in range(0,n):
E_0 = simps(N, k, Apw, x[i])[0]
I[i] = permittivity*c*(E_0 * cmp.conj(E_0)).real
Where j is a complex number j = 0 + 1j
I don't really know if what I am doing is anywhere near correct, the lines that are causing the error is line 46 and 36
In your code, f is a complex number. As the error message says, you can subscript (use square braces on) a complex number. For this reason, the expressions f[0:-1:2], f[1::2] and f[2::2] are illegal operations that are producing this error. It seems that maybe you think that f is a list of complex values, rather than a single value?
If you do know that f is a single complex value, then the only operations on it that I can think of are to extract the real and imaginary parts with f.real and f.imag.
I wrote the following code to calculate a probability. I know the formula I used is correct. The code gives reasonable results for small values of m and n. However, for the large values of m and n, the result, sumC, is outside the interval [0,1] which is not expected. The variable iter takes large values which may be the reason. How can I handle this problem?
import math
from scipy.special import comb
n = 50
m = 100
k = 15
P=[]
sumC = 0
for j in range(k, m+1):
if not (n-j < 0):
iter = (-1)**(j+k) * comb(j, k, exact=True) * comb(m, j, exact=True) * math.factorial(n) * (m-j)**(n-j) /( (m)**(n) * math.factorial(n-j))
sumC = sumC + iter
print(sumC )
Using the Python mpmath arbitrary precision library with 50 digits of precision produces a value in [0, 1] range.
from scipy.special import comb
from mpmath import fac, mp
mp.dps = 50; mp.pretty = True
def compute_prob(k, m, n):
""" Original summation, but using factorial ('fac') from mpmath """
sumC = 0
for j in range(k, m+1):
if not (n-j < 0):
iter_ = (-1)**(j+k) * comb(j, k, exact=True) * comb(m, j, exact=True) * fac(n) * (m-j)**(n-j) /( (m)**(n) * fac(n-j))
sumC = sumC + iter_
return sumC
n = 50
m = 100
k = 15
print(compute_prob(k, m, n))
Output
0.000054845306977312907595945622368606216050228369266162
In the following code I have implemented Simpsons Rule in Python. I have attempted to plot the absolute error as a function of n for a suitable range of integer values n. I know that the exact result should be 1-cos(pi/2). However my graph doesn't seem to be correct. How can I fix my code to get the correct output? there were two loops and I don't think I implemented my graph coding correctly
def simpson(f, a, b, n):
"""Approximates the definite integral of f from a to b by the composite Simpson's rule, using n subintervals (with n even)"""
h = (b - a) / (n)
s = f(a) + f(b)
diffs = {}
for i in range(1, n, 2):
s += 4 * f(a + i * h)
for i in range(2, n-1, 2):
s += 2 * f(a + i * h)
r = s
exact = 1 - cos(pi/2)
diff = abs(r - exact)
diffs[n] = diff
ordered = sorted(diffs.items())
x,y = zip(*ordered)
plt.autoscale()
plt.loglog(x,y)
plt.xlabel("Intervals")
plt.ylabel("Error")
plt.show()
return s * h / 3
simpson(lambda x: sin(x), 0.0, pi/2, 100)
Your simpson method should just calculate the integral for a single value of n (as it does), but creating the plot for many values of n should be outside that method. as:
from math import pi, cos, sin
from matplotlib import pyplot as plt
def simpson(f, a, b, n):
"""Approximates the definite integral of f from a to b by the composite Simpson's rule, using 2n subintervals """
h = (b - a) / (2*n)
s = f(a) + f(b)
for i in range(1, 2*n, 2):
s += 4 * f(a + i * h)
for i in range(2, 2*n-1, 2):
s += 2 * f(a + i * h)
return s * h / 3
diffs = {}
exact = 1 - cos(pi/2)
for n in range(1, 100):
result = simpson(lambda x: sin(x), 0.0, pi/2, n)
diffs[2*n] = abs(exact - result) # use 2*n or n here, your choice.
ordered = sorted(diffs.items())
x,y = zip(*ordered)
plt.autoscale()
plt.loglog(x,y)
plt.xlabel("Intervals")
plt.ylabel("Error")
plt.show()
Here is the homework assignment I'm trying to solve:
A further improvement of the approximate integration method from the last question is to divide the area under the f(x) curve into n equally-spaced trapezoids.
Based on this idea, the following formula can be derived for approximating the integral:
!(https://www.dropbox.com/s/q84mx8r5ml1q7n1/Screenshot%202017-10-01%2016.09.32.png?dl=0)!
where h is the width of the trapezoids, h=(b−a)/n, and xi=a+ih,i∈0,...,n, are the coordinates of the sides of the trapezoids. The figure above visualizes the idea of the trapezoidal rule.
Implement this formula in a Python function trapezint( f,a,b,n ). You may need to check and see if b > a, otherwise you may need to swap the variables.
For instance, the result of trapezint( math.sin,0,0.5*math.pi,10 ) should be 0.9979 (with some numerical error). The result of trapezint( abs,-1,1,10 ) should be 2.0
This is my code but It doesn't seem to return the right values.
For print ((trapezint( math.sin,0,0.5*math.pi,10)))
I get 0.012286334153465965, when I am suppose to get 0.9979
For print (trapezint(abs, -1, 1, 10))
I get 0.18000000000000002, when I am suppose to get 1.0.
import math
def trapezint(f,a,b,n):
g = 0
if b>a:
h = (b-a)/float(n)
for i in range (0,n):
k = 0.5*h*(f(a+i*h) + f(a + (i+1)*h))
g = g + k
return g
else:
a,b=b,a
h = (b-a)/float(n)
for i in range(0,n):
k = 0.5*h*(f(a + i*h) + f(a + (i + 1)*h))
g = g + k
return g
print ((trapezint( math.sin,0,0.5*math.pi,10)))
print (trapezint(abs, -1, 1, 10))
Essentially, your return g statement was indented, when it should not have been.
Also, I removed your duplicated code, so it would adhere to "DRY" "Don't Repeat Yourself" principle, which prevents errors, and keeps code simplified and more readable.
import math
def trapezint(f, a, b, n):
g = 0
if b > a:
h = (b-a)/float(n)
else:
h = (a-b)/float(n)
for i in range (0, n):
k = 0.5 * h * ( f(a + i*h) + f(a + (i+1)*h) )
g = g + k
return g
print ( trapezint( math.sin, 0, 0.5*math.pi, 10) )
print ( trapezint(abs, -1, 1, 10) )
0.9979429863543573
1.0000000000000002
This variation reduces the complexity of branches and reduces number of operations. The summation in last step is reduced to single operation on an array.
from math import pi, sin
def trapezoid(f, a, b, n):
if b < a:
a,b = b, a
h = (b - a)/float(n)
g = [(0.5 * h * (f(a + (i * h)) + f(a + ((i + 1) * h)))) for i in range(0, n)]
return sum(g)
assert trapezoid(sin, 0, 0.5*pi, 10) == 0.9979429863543573
assert trapezoid(abs, -1, 1, 10) == 1.0000000000000002
I would like to add the birthday paradox continuation of the elliptic curve factorization algorithm to my collection of factoring programs. Brent describes the algorithm in two papers, Montgomery also describes the algorithm, and I am trying to implement the algorithm according to a detailed description by Bosma and Lenstra. Here is what I have so far, in Python, which you can run at ideone.com/vMXSab:
# lenstra's algorithm per bosma/lenstra
from random import randint
from fractions import gcd
def primes(n):
b, p, ps = [True] * (n+1), 2, []
for p in xrange(2, n+1):
if b[p]:
ps.append(p)
for i in xrange(p, n+1, p):
b[i] = False
return ps
def bezout(a, b):
if b == 0: return 1, 0, a
q, r = divmod(a, b)
x, y, g = bezout(b, r)
return y, x-q*y, g
def add(p, q, a, b, m):
if p[2] == 0: return q
if q[2] == 0: return p
if p[0] == q[0]:
if (p[1] + q[1]) % m == 0:
return 0, 1, 0 # infinity
n = (3 * p[0] * p[0] + a) % m
d = (2 * p[1]) % m
else:
n = (q[1] - p[1]) % m
d = (q[0] - p[0]) % m
x, y, g = bezout(d, m)
if g > 1: return 0, 0, d # failure
z = (n*x*n*x - p[0] - q[0]) % m
return z, (n * x * (p[0] - z) - p[1]) % m, 1
def mul(k, p, a, b, m):
r = (0,1,0)
while k > 0:
if k % 2 == 1:
r = add(p, r, a, b, m)
if r[2] > 1: return r
k = k // 2
p = add(p, p, a, b, m)
if p[2] > 1: return p
return r
def lenstra1(n, limit):
g = n
while g == n:
q = randint(0, n-1), randint(0, n-1), 1
a = randint(0, n-1)
b = (q[1]*q[1] - q[0]*q[0]*q[0] - a*q[0]) % n
g = gcd(4*a*a*a + 27*b*b, n)
if g > 1: return 0, g # lucky factor
for p in primes(limit):
pp = p
while pp < limit:
q = mul(p, q, a, b, n)
if q[2] > 1:
return 1, gcd(q[2], n)
pp = p * pp
return False
def parms(b1):
b2 = 10 * b1
er = [(1,31), (2,63), (3,127), (6,255), (12,511), \
(18,511), (24,1023), (30,1023), (60,2047)]
prev = 1,31
for (e, r) in er:
if e*e > b1/1250: break
prev = e, r
e, r = prev
rBar = int(round(b2/r))
u = randint(0, pow(2,30)//(e+2))
v = randint(0, pow(2,30)//(e+2))
uBar = randint(0, pow(2,30)//(e+2))
vBar = randint(0, pow(2,30)//(e+2))
return b2, e, r, rBar, u, v, uBar, vBar
def lenstra2(n, b1):
g = n
while g == n:
q = randint(0, n-1), randint(0, n-1), 1
a = randint(0, n-1)
b = (q[1]*q[1] - q[0]*q[0]*q[0] - a*q[0]) % n
g = gcd(4*a*a*a + 27*b*b, n)
if g > 1: return 0, g # lucky factor
for p in primes(b1):
pp = p
while pp < b1:
q = mul(p, q, a, b, n)
if q[2] > 1: return 1, gcd(q[2], n)
pp = p * pp
b2, e, r, rBar, u, v, uBar, vBar = parms(b1)
f = [1] * (r+1)
for i in range(1, r):
p = mul(pow(u*i+v,e), q, a, b, n)
if p[2] > 1: return 2, gcd(p[2], n)
f[i] = (f[i-1] * (q[0] - p[0])) % n
d = 1
for j in range(1, rBar):
pBar = mul(pow(uBar*j+vBar,e), q, a, b, n)
if pBar[2] > 1: return 3, gcd(pBar[2], n)
t = 0
for i in range(0, r):
t = (t + p[0] * f[i]) % n
d = (d * t) % n
g = gcd(d, n)
if 1 < g < n: return 4, g
return False
The primes function implements a simple version of the Sieve of Eratosthenes, returning a list of prime numbers less than n, and the bezout function implements the extended Euclidean algorithm, returning the inverse of a, the inverse of b, and their greatest common divisor. The elliptic arithmetic is given by the add and mul functions; add returns a "point" (0, 0, d) to signal a non-invertible denominator, mul propagates it, and uses of mul in the factoring functions must check it each time mul is called. Function lenstra1 is a simple one-stage version of elliptic curve factorization, and works properly.
Function lenstra2 and its auxiliary function parms are my attempt to implement the algorithm given in the Bosma/Lenstra paper cited above. I'm first trying to get a basic version working, as described in section 6.1, without considering the optimizations in sections 6.4 and 6.7. I think the calculations in parms are correct. The function runs, but always returns False, indicating that it did not find a factor, or it returns after an early break in the elliptic arithmetic before completing the algorithm and returning from the final gcd calculation. I think the problem is in the computation of the coefficients of f, and in the use of f to calculate d.
So my questions:
Have I correctly calculated the coefficients of f?
Have I correctly calculated the value of d?
How do I implement the optimizations of sections 6.4 and 6.7? I don't understand either of them.
How do I implement the Suyama curve of section 5.1 using Weierstrass coordinates?
Many thanks.