The code below is used to find the x* using Gradient Descent and the problem here is that the final result of req8 is -1.00053169969469 and when I round it, it results in -1.00000000000000.
How can I round to get -1.0 or -1.00 instead, without using any other module?
from sympy import *
import numpy as np
global x, y, z, t
x, y, z, t = symbols("x, y, z, t")
def req8(f, eta, xi, tol):
dx = diff(f(x), x)
arrs = [xi]
for i in range(100):
x_star = arrs[-1] - eta * round(dx.subs(x, arrs[-1]), 7)
if abs(dx.subs(x, x_star)) < tol:
break
arrs.append(x_star)
print(arrs[-1])
print(round(arrs[-1], 2))
def f_22(x):
return x**2 + 2*x - 1
req8(f_22, 0.1, -5, 1e-3)
Use the format function to print your rounded result with the desired number of digits (2, in the example below):
print("{:.2f}".format(round(arrs[-1], 2)))
EDIT: as pointed out by #SultanOrazbayev, rounding is no longer necessary here and you may print your result using the following expression:
print("{:.2f}".format(arrs[-1]))
Related
I tried to plot pairs (x,y) which are solutions to the equation y^2 + y = x^3 + y(x^2) using the following code:
import numpy as np
y = np.arange(0,12,.01)
x = np.arange(0,18,.01)
for i in enumerate(y):
for j in enumerate(x):
if (i**2)+i == j**3 + i*(j**2):
plot(i,j)
However, I got the following error:
"TypeError: unsupported operand type(s) for ** or pow(): 'tuple' and 'int'"
Anybody can help me to figure out how can I plot solutions?
I have also another question: Is it possible to store each pair of solution in a variable so we can use specific pairs of solutions in the future?
enumerate yields (index, value) tuples, you can use unpacking to get each one separately in the loop header:
for i_ind, i in enumerate(y):
for j_ind, j in enumerate(x):
I suggest you modify your formulation and plot the square difference between LHS and RHS instead:
x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(x, y)
def F(p):
x, y = p
v = y**2 + y - x**3 - y * (x**2)
return v**2
Z = F((X, Y))
plt.contourf(X, Y, Z)
plt.colorbar()
idx = np.where(np.abs(Z) < 1e-4)
plt.scatter(X[idx], Y[idx], marker='+', color='w')
You can also use scipy.optimize.fmin(F, [1, 1]) to get the exact solution of F=0, where [1, 1] is your initial guess. In this case, different initial guess will result in different solution.
while the other answer describes the mechanical transform needed to stop that exception being thrown, it's not going to get any points in your plot. Numpy is a numeric library, while you want/need to solve the equation.
numpy.arange(0, 12, 0.01) generates a finite series of numbers starting at 0 and incrementing by 0.01 until it hits 12. you give an equation above which is mostly translated into Python code, and evaluate it on these finite series of numbers and ask it to plot values where both expressions evaluate to the same number. floats in Python are 64-bit floats so this equality is checked to approx 15 decimal digits, which will basically not happen for your numbers.
instead of doing what you're attempting to do you want to use something like Sympy which would actually help you. to get started we do:
from sympy import symbols, solveset, simplify, lambdify
x, y = symbols('x y')
eq1 = y**2 + y
eq2 = x**3 + x*y**2
ss = solveset(eq1 - eq2, y)
which names a pair of symbols, puts them into some equations and solves for when eq1 == eq2 (equivalently when their difference is zero).
next you want to plot these solutions, which can be done in this case:
import numpy as np
import matplotlib.pyplot as plt
xx = np.linspace(-5, 4, 101)
for eq in ss:
fn = lambdify(x, eq)
yy = fn(xx)
# hide complex solutions
yy[~np.isreal(yy)] = np.nan
plt.plot(xx, np.real(yy), label=simplify(eq))
plt.legend()
this starts by pulling in numpy and matplotlib, then sampling points on the x-axis at which we want to evaluate the functions, then loop through solutions turning them into Python functions that we can evaluate to get numeric answers, next we evaluate this on our sampled points, discard complex solutions, and plot the results.
this gives:
the gap around x = -4.5 is due to sampling at this point being sparse. we can check by evaluating our equations at x=-4.5, y=10, and I get ~110 for both equations
In order to circumvent the cauchy principle value, I tried to integrate an integral using a small shift iε into the complex plane to evade the pole. However, as can be inferred from the figure below, the result is pretty bad. The code for this result is shown below. Do you have ideas how to improve this method? Why is it not working? I already tried changing ε or the limit in the integral.
Edit: I included the method "cauchy" with the principle value, which seems not to work at all.
import matplotlib.pyplot as plt
from scipy.integrate import quad
import numpy as np
def cquad(func, a, b, **kwargs):
real_integral = quad(lambda x: np.real(func(x)), a, b, limit = 200,**kwargs)
imag_integral = quad(lambda x: np.imag(func(x)), a, b, limit = 200,**kwargs)
return (real_integral[0] + 1j*imag_integral[0], real_integral[1:], imag_integral[1:])
def k_(a):
ϵ = 1e-32
return (cquad(lambda x: np.exp(-1j*x)/(x**2 - a**2 - 1j*ϵ),-np.inf,np.inf)[0])
def k2_(a):
return (cquad(lambda x: np.exp(-1j*x)/(x**2 - a**2),-1e6,1e6, weight='cauchy', wvar = a)[0])
k = np.vectorize(k_)
k2 = np.vectorize(k2_)
fig, ax = plt.subplots()
a = np.linspace(-10,10,300)
ax.plot(a,np.real(k(a)),".-",label = "numerical result")
ax.plot(a,np.real(k2(a)),".-",label = "numerical result (cauchy)")
ax.plot(a, - np.pi*np.sin(a)/a,"-",label="analytical result")
ax.set_ylim(-5,5)
ax.set_ylabel("f(x)")
ax.set_xlabel("x")
ax.set_title(r"$\mathcal{P}\int_{-\infty}^{\infty} \frac{e^{-i y}}{y^2 - x^2}\mathrm{d}y = -\frac{\pi\sin(x)}{x}$")
plt.legend()
plt.savefig("./bad_result.png")
plt.show()
The main problem is that the integrand has poles at both x=a and
x=-a. ev-br's post show how
to deal with a pole at x=a. All that's needed then is to find a way to
massage the integral into a form that avoids integrating through the other pole
at x=-a. Taking advantage of evenness allows us to "fold the integral over",
so instead of having two poles we just need to deal with one pole at x=a.
The real part of
np.exp(-1j*x) / (x**2 - a**2) = (np.cos(x) - 1j * np.sin(x)) / (x**2 - a**2)
is an even function of x so integrating the real part from x = -infinity to
infinity would equal twice the integral from x = 0 to infinity. The
imaginary part of the integrand is an odd function of x. The integral from x = -infinity to infinity equals the integral from x = -infinity to 0, plus
the integral from x = 0 to infinity. These two parts cancel each other out
since the (imaginary) integrand is odd. So the integral of the imaginary part equals 0.
Finally, using ev-br's suggestion, since
1 / (x**2 - a**2) = 1 / ((x - a)(x + a))
using weight='cauchy', wvar=a implicitly weights the integrand by 1 / (x - a) thus allowing us to reduce the explicit integrand to
np.cos(x) / (x + a)
Since the integrand is an even function of a, we can assume without loss of generality that a is positive:
a = abs(a)
Now integrating from x = 0 to infinity avoids the pole at x = -a.
import matplotlib.pyplot as plt
from scipy.integrate import quad
import numpy as np
def cquad(func, a, b, **kwargs):
real_integral = quad(lambda x: np.real(func(x)), a, b, limit=200, **kwargs)
imag_integral = quad(lambda x: np.imag(func(x)), a, b, limit=200, **kwargs)
return (real_integral[0] + 1j*imag_integral[0], real_integral[1:], imag_integral[1:])
def k2_(a):
a = abs(a)
# return 2*(cquad(lambda x: np.exp(-1j*x)/(x + a), 0, 1e6, weight='cauchy', wvar=a)[0]) # also works
# return 2*(cquad(lambda x: np.cos(x)/(x + a), 0, 1e6, weight='cauchy', wvar=a)[0]) # also works, but not necessary
return 2*quad(lambda x: np.cos(x)/(x + a), 0, 1e6, limit=200, weight='cauchy', wvar=a)[0]
k2 = np.vectorize(k2_)
fig, ax = plt.subplots()
a = np.linspace(-10, 10, 300)
ax.plot(a, np.real(k2(a)), ".-", label="numerical result (cauchy)")
ax.plot(a, - np.pi*np.sin(a)/a, "-", label="analytical result")
ax.set_ylim(-5, 5)
ax.set_ylabel("f(x)")
ax.set_xlabel("x")
ax.set_title(
r"$\mathcal{P}\int_{-\infty}^{\infty} \frac{e^{-i y}}{y^2 - x^2}\mathrm{d}y = -\frac{\pi\sin(x)}{x}$")
plt.legend()
plt.show()
You can use instead the weight="cauchy" argument to quad.
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html
I have attempted to solve the following problem. I tried to solve it first with a set step size h using 0.1. However I need to change this in my code and use a for loop to loop through the values 0,1,..,20. I am a little confused how to do this problem but I was hoping to get some help with fixing the code I produced so far. Thanks!
import numpy as np
from math import sin
def derivative(func , x, h ):
for h in range(20):
return (func(x+h)-func(x))/h
def f(x):
return sin(x)
print(derivative(f, pi/4))
Gives the output
0.6706029729039897
MY EDIT:
def derivative(func , x, h ):
for h in range(20):
return (func(x+h)-func(x))/h
The exercise is asking you to compute the derivative using varying precision (represented using the variable h), and compare that to the exact/real derivative of the function.
Let h = 10 ^ -j, with j varying from 0 to 20. This means h will go (discretely) from 10⁻⁰ to 10⁻²⁰. You can use a for-loop and the range(...) function for that. Then pass that to the derivative function (to which you can a third parameter for the value of h)
def derivative(func, x, h):
return (func(x + h) - func(x)) / h
Next, you need to compare that to the exact derivative. The function f(x) = sin(x) has a known (exact) derivative which is cos(x). In math notation, d(sin x)/dx = cos x. This means that for any x, cos(x) will give you the exact derivative of sin at that x.
So you need to compare the result of the derivative(...) function to the value of cos(x). This will give you the difference. You can then use the basic Python function abs(x) to get the absolute value of that difference, which will give you the absolute difference, which is the desired result. Do that for each j from 0 to 20 and store the results somewhere, in an array or a dict.
from math import sin, cos, pi
x = pi / 4
diffs = {}
for j in range(21): # range is exclusive so range(21) will stop at 20
h = 10 ** -j
deriv = derivative(sin, x, h)
exact = cos(x)
diff = abs(deriv - exact)
diffs[h] = diff
Then, you can use pyplot's loglog function to plot those results on a graph, passing as X the range(...) result and as Y the array containing the results.
import matplotlib.pyplot as plt
ordered = sorted(diffs.items())
x, y = zip(*ordered)
plt.loglog(x, y)
I am reading Data Science From Scratch by Joel Grus, and am stuck on understanding how a simple difference quotient function works using python.
Here is the code:
f is a function of a one variable function, dependent on x, as h approaches 0.
def difference_quotient(f, x, h):
return (f(x + h) - f(x)) / h
I understand that this is just the equation for finding the limit, and in this case the derivative, but I don't see how the script works. What arguments would you put into the function that would allow for a return statement of f(something) and not f*(something). So far I keep getting errors such as 'float'/'dict' object is not callable.
f is the function you are trying to find the derivative/difference quotient of at x.
Try this code: (python 3)
def difference_quotient(f, x, h):
return (f(x + h) - f(x)) / h
def func(x):
# this is f of x, the function you are taking the derivative of
return x * x
print(difference_quotient(func, 2, 0.001))
"Someone" has answered your question but you (and future readers) may find this supplementary information useful.
To get an accurate approximation of the derivative you need to make h fairly small. However, if you make it too small then you actually lose accuracy due to the limited precision of Python floats. You can get more precision by using the decimal module. However, that module only supports simple arithmetic operators and the square root function. If you need fancier functions like trigonometric or exponential functions, then you can use a 3rd-party package arbitrary-precision mathemtaics package such as the excellent mpmath, although if you do use mpmath then you'd probably use its numerical derivative functions.
FWIW, you can make the derivative approximation more accurate (for a given h) by making x the middle of the interval. Here's a short demo:
def dfa(f, x, h):
return (f(x + h) - f(x)) / h
def dfb(f, x, h):
hh = 0.5 * h
return (f(x + hh) - f(x - hh)) / h
# The function
def func(x): return x**3 + x*x + x + 1
# Its exact derivative
def dfunc(x): return 3*x*x + 2*x + 1
h = 0.001
for i in range(10):
x = 1 + 0.1 * i
print(x, dfunc(x), dfb(func, x, h), dfa(func, x, h))
output
1.0 6.0 6.00000024999936 6.004000999999093
1.1 6.830000000000001 6.830000249999024 6.8343009999995985
1.2 7.719999999999999 7.72000024999997 7.724600999999609
1.3 8.67 8.670000249998644 8.674900999999124
1.4 9.68 9.680000249999487 9.685200999998145
1.5 10.75 10.750000249998948 10.755500999998446
1.6 11.880000000000003 11.880000249998801 11.885800999996476
1.7000000000000002 13.070000000000002 13.07000024999816 13.07610099999934
1.8 14.32 14.320000249997022 14.326400999998157
1.9 15.629999999999999 15.630000249997167 15.636700999996478
Here are the results for the exponential function.
from math import exp
def dfa(f, x, h):
return (f(x + h) - f(x)) / h
def dfb(f, x, h):
hh = 0.5 * h
return (f(x + hh) - f(x - hh)) / h
func = dfunc = exp
h = 0.001
for i in range(10):
x = 1 + 0.1 * i
print(x, dfunc(x), dfb(func, x, h), dfa(func, x, h))
output
1.0 2.718281828459045 2.718281941720413 2.7196414225332255
1.1 3.0041660239464334 3.0041661491195804 3.005668607777512
1.2 3.3201169227365472 3.320117061074157 3.3217775346887635
1.3 3.6692966676192444 3.669296820505874 3.6711319276547805
1.4 4.0551999668446745 4.0552001358102885 4.057228242863253
1.5 4.4816890703380645 4.481689257074706 4.483930662008362
1.6 4.953032424395115 4.953032630771403 4.955509766318755
1.7000000000000002 5.473947391727201 5.473947619807795 5.476685277975513
1.8 6.0496474644129465 6.049647716480422 6.0526732966712515
1.9 6.6858944422792685 6.685894720857455 6.689238504094419
Note that dfb is not foolproof: if you're trying to find the derivative for an x value that's near a pole or discontinuity, then shifting the interval to include the pole or discontinuity can give erroneous results. Of course, you can get the same problem with dfa, eg if f(x) = 1/x and x is a negative number but x+h is positive.
I want to carry out the following partial integration of a 2-D gaussian function of four variables (x, y, alpha and beta), with respect to only x and y, as follows. In the end I want the answer to be a function of alpha and beta only.
I wrote the following code in python to execute the above mentioned integral.
from sympy import Symbol
from sympy import integrate
from math import e
alpha = Symbol('alpha')
beta = Symbol('beta')
x = Symbol('x')
y = Symbol('y')
n = 2
value = integrate( e**( -(x - alpha)**n - (y - beta)**n ), (x, -1, 1), (y, -1, 1) )
However I get the following error:
sympy.polys.polyerrors.DomainError: there is no ring associated with RR
The above mentioned integrate function works fine for n=1. However it breaks down for n>1.
Am I doing something wrong?
Welcome to SO!
Interestingly it works when you substitute alpha and beta into the integral bounds. Try:
from IPython.display import display
import sympy as sy
sy.init_printing() # LaTeX like pretty printing forIPython
alpha, beta, x, y = sy.symbols("alpha, beta, x, y", real=True)
f = sy.exp(-x**2 - y**2) # sy.exp() is better than the numeric constant
val = sy.integrate(f, (x, -1+alpha, 1+alpha), (y, -1+beta, 1+beta))
display(val)