My programm aims in defining the integral of a given function between two numbers (x1,x2),using n trapezoids.As it seems,my department's auto evaluating programm gives different answers than the ones of mine.Problem is that i cant find anything wrong in my code...
def funct(x):
val= -(1./6)*(x-1)*(x-2)*(x+2)*(x-4)
return val
x1,x2,n=input()
Dx=float(x2-x1)/n
Sum=0
i=x1+Dx
while i<x2:
val=funct(i)
Sum+=val
i+=Dx
Sum=2*Sum
val1=funct(x1)
val2=funct(x2)
S=(Dx/2)*(val1+val2+Sum)
print "%.3f" %S
Due to rounding issues, your while cycle always includes last value of x, try using exact integer arithmetic
x0, x1 = -88.787529, 83.494648
n = 1942
dx = (x1-x0)/n
s = 0
i = 1
while i < n:
# if we allow i == n, in the following row we'll have
# x0 + n*dx = x0 + n * (x1-x0) / n = x0 + x1 - x0 = x1
# but we want to exclude the last term
s = s + funct(x0+i*dx)
i = i + 1
result = (s + funct(x0)/2.0 + funct(x1)/2.0)*dx
I know this is probably some sort of homework question, but in general, don't reinvent the wheel:
import numpy
def funct(x):
return -(1./6)*(x-1)*(x-2)*(x+2)*(x-4)
x1, x2 = -88.787529, 83.494648
n = 1942
# n "panels", n+1 points
x = numpy.linspace(x1, x2, n+1)
y = funct(x)
result = numpy.trapz(y, x)
Related
I need to find the lower and upper intersections with the x-axis of a curve given by
y=f(x)=10⋅exp(sin(x))−(x^2)/2
In order to find the arc length of the curve, in Python
I have already tried two methods, The secant method which I cannot get to work at all. And the Newton Method which finds one intersection.
from math import exp
from math import sin
from math import cos
def func( x ):
return 10*exp(sin(x))-(x**2)/2
def derivFunc( x ):
return 10*exp(sin(x))*cos(x)-x
def newtonRaphson( x ):
h = func(x) / derivFunc(x)
while abs(h) >= 0.0001:
h = func(x)/derivFunc(x)
x = x - h
print("The value of the root is : ",
"%.4f"% x)
x0 = -20
newtonRaphson(x0)
which gives
The value of the root is : -5.7546
Then the second method
import math
from math import exp
from math import sin
def f(x):
f = 10*exp(sin(x))-(x**2)/2
return f;
def secant(x1, x2, E):
n = 0; xm = 0; x0 = 0; c = 0;
if (f(x1) * f(x2) < 0):
while True:
x0 = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
c = f(x1) * f(x0);
x1 = x2;
x2 = x0;
n += 1;
if (c == 0):
xm = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
if(abs(xm - x0) < E):
print("Root of the given equation =",round(x0, 6));
print("No. of iterations = ", n);
print("Can not find a root in ","the given inteval");
x1 = 0; x2 = 1;
E = 0.0001;
secant(x1, x2, E);
Only results in
NameError: name 'x2' is not defined
Yet whenever I've tried defining the characters it won't run
I would like to be able to get the upper and lower intersections with the x-axis, So I can find the arc length. And is there a way to get it to plot the graph as well
About the Newton-Raphson method:
Normal behaviour
It works mostly as intended. The method may converge to a single root only, which depends on the starting point. To get another root, you need another starting point.
Your function yields:
>>> newtonRaphson(-20)
-5.7545790362989
>>> newtonRaphson(5)
3.594007784799419
Which seems to be correct.
Bugs
The Newton-Raphson method isn't guaranteed to converge, it may enter an ifinite loop, in which case your program would hang indefinitely, or the derivative at a point may be zero, in which case you can't compute h. You need to handle these cases.
Style
There is a lot of things that can be inproved:
The bug must be fixed
You Newton-Raphson method currently only works for one function only. You should pass the function and derivative as arguments, so you can apply the method to any function you want.
The desired precision and max iterations can also be passed as arguments
It's bad practice to print within the function. You should return the value instead, so you can decide to do whatever with the result.
you should follow PEP8's style guidelines
include a docstring if you plan to reuse it (wich is very possible, it is a very useful tool!)
My take on the method:
def newton_raphson(f, df, x, epsilon = 0.0001, maxiter = 1000):
""" Estimates the root of a function.
Gives an estimate to the required precision of a root of the given function
using the Newton-Raphson method.
Raises an Exception if the Newton-Raphson method doesn't converge in the
specified number of iterations.
Raises a ZeroDivisionError if the derivative is zero at a calculated point
:param f: The function
:param df: The function's derivative
:param x: the starting point for the method
:param epsilon: The desired precision
:param maxiter: The maximum number of iterations
:return: The root extimate
:rtype: float
"""
for _ in range(maxiter):
h = f(x)/df(x)
if abs(h) < epsilon:
return x
x = x - h
raise Exception("Newton Raphson method didn't "
+ "converge in {} iterations".format(maxiter))
usage:
>>> print(newton_raphson(func, derivFunc, 20))
-5.7545790362989
>>> print(newton_raphson(func, derivFunc, 5, 0.1, 100))
3.5837828560043477
>>> print(newton_raphson(func, derivFunc, 5, 0.001, 100))
3.594007784799419
>>> print(newton_raphson(func, derivFunc, 5, 1e-9, 4))
Traceback (most recent call last):
(...)
Exception: Newton Raphson method didn't converge in 4 iterations
About the secant method:
I'm not as familiar with that one, so I'll just mention the error you have is due to bad identation. Here it is fixed:
def secant(x1, x2, E):
n = 0; xm = 0; x0 = 0; c = 0;
if (f(x1) * f(x2) < 0):
while True:
x0 = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
c = f(x1) * f(x0);
x1 = x2;
x2 = x0;
n += 1;
if (c == 0):
xm = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
if(abs(xm - x0) < E):
print("Root of the given equation =",round(x0, 6));
print("No. of iterations = ", n);
print("Can not find a root in ","the given inteval");
If you plan to propely implement this method, the remarks about the Newton-Raphson method still hold.
I am trying to use SageMath for something that involves a lot of manipulation of boolean polynomials.
Here are some examples of what a coefficient vector is:
x0*x1*x2 + 1 has coefficient vector 10000001
x1 + x0 + 1 has coefficient vector 11100000
x1 + x0 has coefficient vector 01100000
(x0 is the least significant bit.)
The problem is that Sage's API doesn't seem to encourage direct manipulation of monomials or coefficient vectors, probably because the data structures it uses internally are ZDDs instead of bit arrays.
sage: P
x0*x1*x2 + x0*x1 + x0*x2 + x0 + x1*x2 + x1 + x2 + 1
sage: list(P.set())
[x0*x1*x2, x0*x1, x0*x2, x0, x1*x2, x1, x2, 1]
sage: P.terms()
[x0*x1*x2, x0*x1, x0*x2, x0, x1*x2, x1, x2, 1]
In this code, it appears that the problem is that the endianness is the opposite of what one may expect; which would be with x0 being the least significant bit.
The problem is actually more than that. For example:
#!/usr/bin/env python
from sage.all import *
from sage.crypto.boolean_function import BooleanFunction
# "input_str" is a truth table.
# Returns a polynomial that has that truth table.
def truth_str_to_poly(input_str):
# assumes that the length of input_str is a power of two
num_vars = int(log(len(input_str),2))
truth_table = []
# convert string to list of ints expected by BooleanFunction
for i in list(input_str):
truth_table.append(int(i))
B = BooleanFunction(truth_table)
P = B.algebraic_normal_form()
return P
# Return the polynomial with coefficient vector 1,1,...,1.
# (This is neccessary because we can't directly manipulate coef. vectors.)
def super_poly(num_vars):
input_str = ["0"]*(2**num_vars)
input_str[0] = "1"
input_str = "".join(input_str)
return truth_str_to_poly(input_str)
# Return the coefficient vector of P.
# This is the function that is broken.
def poly_to_coef_str(P, num_vars):
res = ""
#for i in super_poly(num_vars).terms():
for i in list(super_poly(num_vars).set()):
res += str(P.monomial_coefficient(i))
return res
num_vars = 3
print(super_poly(num_vars).monomials())
# This should have coefficient vector "01000000" = x0
input_poly = "01010101"
P = truth_str_to_poly(input_poly) # Gives correct result
res = poly_to_coef_str(P, 3)
print(" in:"+input_poly)
print("out:"+res)
Output:
[x0*x1*x2, x0*x1, x0*x2, x0, x1*x2, x1, x2, 1]
in:01010101
out:00010000
This means that it's not just getting the endianness wrong, it's somehow treating the place value of variables inconsistently.
Is there a better way to do this?
I have written the following code:
import math
import scipy
def steffensen(equation, f_prime, x, er, N):
for i in range(1, N):
y1 = x
r = equation(x)
dx = (-r)/(f_prime(x))
y2 = y1 + dx
y3 = y2 + dx
x = y1-(((y2-y1)**2)/(y3-2*y2+y1))
z = abs(equation(x))
print("|f(x)| = %e"%z)
if z < e:
print("Converged!")
break
return x
#This will be used for testing
def equation(x):
return math.exp(-x**2 + x)-(0.5*x)
def f_prime(x):
return (1-2*x)*math.exp(x-(x**2))-0.5
#def main():
x0 = 1
N = 5
er = 1e-6
x = steffensen(equation, f_prime, x0, er, N)
print("Finished!")
When compiled, the code returns saying that there is a zero division error: float division by zero on the line that says: x = y1-(((y2-y1)**2)/(y3-2*y2+y1)). When computed by hand, I don't get 0. Please help me find the bug.
You're getting a zero division error because your program divides by zero. The question you should focus on is "how do I figure out what's wrong?" Do it by adding a diagnostic statement just before the line that throws the error. I'd start with this one:
print(i, dx, y1, y2, y3, y3-2*y2+y1)
You'll get this output,
1 0.3333333333333333 1 1.3333333333333333 1.6666666666666665 0.0
showing that the error occurs on the first pass through the loop (i == 1), and that dx has the value 1/3. Take it from there, and figure out why your program diverges from the calculation you did by hand.
I am trying to solve the following equation in python using the scipy.odeint function.
Currently I am able to implement this form of the equation
in python using the following script:
def dY(y1, x):
a = 0.001
yin = 1
C = 0.01
N = 1
dC = C/N
b1 = 0
return (a/dC)*(yin-y1)+b1*dC
x = np.linspace(0,20,1000)
y0 = 0
res = odeint(dY, y0, x)
plt.plot(t,res, '-')
plt.show()
My problem with the first equation is 'i'. I don't know how to integrate the equation and still be able to provide the current and previous 'y'(yi-1 and yi) values. 'i' is simply a sequence number that is within a range of 0..100.
Edit 1:
The original equation is:
Which I rewrote using y,x,a,b and C
Edit2:
I edited Pierre de Buyl' code and changed the N value. Luckily I have a validation table to validate the outcome against. Unfortunately, the results are not equal.
Here is my validation table:
and here is the numpy output:
Used code:
def dY(y, x):
a = 0.001
yin = 1
C = 0.01
N = 3
dC = C/N
b1 = 0.01
y_diff = -np.copy(y)
y_diff[0] += yin
y_diff[1:] += y[:-1]
return (a/dC)*(y_diff)+b1*dC
x = np.linspace(0,20,11)
y0 = np.zeros(3)
res = odeint(dY, y0, x)
plt.plot(x,res, '-')
as you can see the values are different by an offset of 0.02..
Am I missing something that results in this offset?
The equation is a "coupled" ordinary differential equation (see "System of ODEs" on Wikipedia.
The variable is a vector containing y[0], y[1], etc. To solve the ODE you must feed a vector as the initial condition and the function dY must return a vector as well.
I have modified your code to achieve this result:
def dY(y, x):
a = 0.001
yin = 1
C = 0.01
N = 1
dC = C/N
b1 = 0
y_diff = -np.copy(y)
y_diff[0] += yin
y_diff[1:] += y[:-1]
return (a/dC)*y_diff+b1*dC
I have written the part y[i-1] - y[i] as a NumPy vector operation and special cased the coordinate y[0] (that is the y1 in your notation but arrays start at 0 in Python).
The solution, using an initial value of 0 for all yi is
x = np.linspace(0,20,1000)
y0 = np.zeros(4)
res = odeint(dY, y0, x)
plt.plot(x,res, '-')
I am trying to define the archimedean spiral: when I'm trying to define the inclination angle (incl) of the tangent vector to the orbit ( i.e: tan(incl))
I'm getting an error:
'numpy.ufunc' object does not support item assignment"
and "can't assign to function call"
the same error when I want to calculate cos(incl), and sin(incl).
Any suggestions and helps.
My code is:
T = 100
N = 10000
dt = float(T)/N
D = 2
DII = 10
a = 2.
v = 0.23
omega = 0.2
r0 = v/omega
t = np.linspace(0,T,N+1)
r = v*t
theta = a + r/r0
theta = omega*t
x = r * np.cos(omega*t)
y = r * np.sin(omega*t)
dxdr = np.cos(theta) - (r/r0)*np.sin(theta)
dydr = np.sin(theta) + (r/r0)*np.cos(theta)
dydx = (r0*np.sin(theta) + r*np.cos(theta))/r0*np.cos(theta) - r*np.sin(theta)
np.tan[incl] = dydx
incl = np.arctan((dydx))
### Calculate cos(incl) ,sin(incl) :
np.sin[np.incl] = np.tan(np.incl)/np.sqrt(1 + np.tan(np.incl)*2)
np.cos[incl] = 1/np.sqrt(1 + np.tan(incl)*2)
p1, = plt.plot(xx, yy)
i= 0 # this is the first value of the array
Bx = np.array([np.cos(i), -np.sin(i)])
By = np.array([np.sin(i), np.cos(i)])
n = 1000
seed(2)
finalpositions = []
for number in range(0, 10):
x = []
y = []
x.append(0)
y.append(0)
for i in range(n):
s = np.random.normal(0, 1, 2)
deltaX = Bx[0]*np.sqrt(2*DII*dt)*s[0] + Bx[1]*np.sqrt(2*D*dt)*s[1]
deltaY = By[0]*np.sqrt(2*DII*dt)*s[0] + By[1]*np.sqrt(2*D*dt)*s[1]
x.append(x[-1] + deltaX)
y.append(y[-1] + deltaY)
finalpositions.append([x[-1], y[-1]])
p2, = plt.plot(finalpositions[:,0],finalpositions[:,1],'*')
plt.show()
The error message is correct, you are trying to assign to a function! I think you're trying to compute a value that represents the sin, cos or tan of a value, but that doesn't mean you need to assign to np.sin, etc. What you want is to calculate the value which represents the trig function, and then use the inverse trig function to get the angle:
## np.tan[incl]= dydx ## np.tan is a function, so you cannot index it like an array, and you should not assign to it.
incl = np.arctan((dydx)) ## this is all you need to get "incl"
### Calculate cos(incl) ,sin(incl) :
## NOTE: you already have the angle you need!! No need for a complicated formulate to compute the sin or cos!
sin_incl = np.sin(incl)
cos_incl = np.cos(incl)
EDIT: One additional comment...np is a module that contains lots of numeric methods. When you calculate incl, it is not part of np! So there is no need to reference it like np.incl. Just use incl.
EDIT2: Another problem I found is this line:
dydx = (r0*np.sin(theta) + r*np.cos(theta))/r0*np.cos(theta) - r*np.sin(theta)
To calculate dydx, you're just dividing dydr by dxdr, but that's not what your code does! You need parens around the denominator like this:
dydx = (r0*np.sin(theta) + r*np.cos(theta))/(r0*np.cos(theta) - r*np.sin(theta))