Contradictiry values for the same calculation in python - python

Consider the following two results
import numpy as np
(1/21) * np.log( (1/21) / (3/21) * (3/21))
which results in
-0.14497725893921062
and the same calculation as follows
import numpy as np
x = 0.14285714285714285
y = 0.14285714285714285
xy = 0.047619047619047616
xy * np.log(xy / (x * y))
which results in
0.040347517161295414
Both calculations are same, but results has so much gap. What is the issue here?
And which one is recommended, if its not a subjective question?

Because multiplication and divison have same precedence at Python and Python reads them from left to right.
for example:
x, y, z = 2, 4, 8
these are completely different:
x / y * z == x / (y * z)
>>>False
left side is 4.0 and right side is 0.0625
ps:
Parentheses have the highest precedence and can be used to force an expression to evaluate in the order you want.

Related

scipy.optimize.minimize two different outputs for the same(?) input

I have a function func(x). I want to know the x for func(x)-7=0. Because there is no exact real answer, I thought minimize would be a good idea.
from scipy.optimize import minimize
def func(x): # testing function which leads to the same behaviour
return (x * 5 + x * (1 - x) * (6-3*x) * 5)
def comp(x): # comparison function which should get zero
return abs(((func(x)) - 7))
x0 = 0.
x_real = minimize(comp, x0) # minimize comparison function to get x
print(x_real.x)
The last print gives me [ 0.7851167]. The following print...
print(comp(x_real.x))
print(comp(0.7851167))
...leads to different outputs:
[ 1.31290960e-08]
6.151420706146382e-09
Can someone explain me this behaviour?
EDIT: I think i understood your question wrong. Rounding the number as you did in the print statements obviously will result in some differences (which are pretty small (around 1e-9)).
To find all x, you should apply some global solution method or start from different intital point to find all local minimas(as seen in the plot).
The equation however has two solutions.
def func(x): # testing function which leads to the same behaviour
return (x * 5 + x * (1 - x) * (6-3*x) * 5)
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-0.1,1,100)
plt.plot(x, func(x)-7)
plt.plot(x, np.zeros(100))
plt.show()
The function:

Get a second implicit derivative with SymPy

we have the follow cell in jupyter kernel python3:
from sympy.interactive.printing import init_printing
from sympy.core.symbol import symbols
from sympy.geometry.util import idiff
init_printing(use_unicode=True)
x = symbols('x')
y = symbols('y')
then just run:
eq = x ** 2 - x * y + y ** 2 - 3
eqd1 = idiff(eq, y, x)
eqd1
we get the correct answer: 2x-y / x-2y
but if run the code:
eqd2 = idiff(eqd1, y, x)
eqd2
we get: x/y but the answer realy is: 18/(x-2y)² or 6(x²-xy+y²)/(x-2y)³
x/y and 18/(x-2y)² don't looks like a equal expression or factorial one of another
Running
eqd2 = idiff(eq, y, x, n=2)
simplify(expand(eqd2))
Produces
6(x2-xy+y2)/(x3-6x2y-12xy2-8y3)
which is the correct result (after a bit more simplification).

Efficiently coding gradient of function

I'm currently trying to code this beastie in Python (using the numpy libraries). The lambda * w is supposed to be outside the summation.
Currently, I've coded the problem using a for loop, and a running total outside; however, this approach takes a long time.
My vectors for y, w, and x are very large - think 100,000s of elements. I was wondering whether there is a simpler way to vectorize the element instead using simple matrix operations instead of looping through the vector one element by another element.
This is my vectorized code:
xty = xtrain.T.dot(ytrain)
e = math.exp(-w_0.T.dot(xty))
gradient = (-xty*(e/1+e)-lambda_var*w_0)
If I understand your problem correctly, you might just have to bite the bullet and go with the loop:
import numpy as np
wave = 1e3
xs, ys, w = np.arange(1, 4), np.arange(4, 7), np.arange(7, 10)
eps = np.zeros(w.T.shape)
for x, y in zip(xs, ys):
eps += -y * np.exp(-y * w.T * x) * x / (1 + np.exp(-y * w.T * x))
print(eps + wave * w)
[ 7000. 8000. 9000.]

Evaluate 1/tanh(x) - 1/x for very small x

I need to compute the quantity
1/tanh(x) - 1/x
for x > 0, where x can be both very small and very large.
Asymptotically for small x, we have
1/tanh(x) - 1/x -> x / 3
and for large x
1/tanh(x) - 1/x -> 1
Anyhow, when computing the expression, already from 10^-7 and smaller round-off errors lead to the expression being evaluated as exactly 0:
import numpy
import matplotlib.pyplot as plt
x = numpy.array([2**k for k in range(-30, 30)])
y = 1.0 / numpy.tanh(x) - 1.0 / x
plt.loglog(x, y)
plt.show()
For very small x, one could use the Taylor expansion of 1/tanh(x) - 1/x around 0,
y = x/3.0 - x**3 / 45.0 + 2.0/945.0 * x**5
The error is of the order O(x**7), so if 10^-5 is chosen as the breaking point, relative and absolute error will be well below machine precision.
import numpy
import matplotlib.pyplot as plt
x = numpy.array([2**k for k in range(-50, 30)])
y0 = 1.0 / numpy.tanh(x) - 1.0 / x
y1 = x/3.0 - x**3 / 45.0 + 2.0/945.0 * x**5
y = numpy.where(x > 1.0e-5, y0, y1)
plt.loglog(x, y)
plt.show()
Use the python package mpmath for arbitrary decimal precision. For example:
import mpmath
from mpmath import mpf
mpmath.mp.dps = 100 # set decimal precision
x = mpf('1e-20')
print (mpf('1') / mpmath.tanh(x)) - (mpf('1') / x)
>>> 0.000000000000000000003333333333333333333333333333333333333333311111111111111111111946629156220629025294373160489201095913
It gets extremely precise.
Look into mpmath plotting. mpmath plays well with matplotlib, which you are using, so this should solve your problem.
Here is an example of how to integrate mpmath into the code you wrote above:
import numpy
import matplotlib.pyplot as plt
import mpmath
from mpmath import mpf
mpmath.mp.dps = 100 # set decimal precision
x = numpy.array([mpf('2')**k for k in range(-30, 30)])
y = mpf('1.0') / numpy.array([mpmath.tanh(e) for e in x]) - mpf('1.0') / x
plt.loglog(x, y)
plt.show()
A probably simpler solution to overcome this is changing the data type under which numpy is operating:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-30, 30, dtype=np.longdouble)
x = 2**x
y = 1.0 / np.tanh(x) - 1.0 / x
plt.loglog(x, y)
plt.show()
Using longdouble as data type does give the proper solution without rounding errors.
I did sightly modify your example, in your case the only thing you need to modify is:
x = numpy.array([2**k for k in range(-30, 30)])
to:
x = numpy.array([2**k for k in range(-30, 30)], dtype=numpy.longdouble)

How to compose function range in Python

So I wish to create a log(y) vs log(x) of the following function in python. I am not sure how the range (w) should be composed to get a good graph. For now I have left it blank.
import numpy as np
import matplotlib.pyplot as plt
w =
y = 1/(1+2.56e-8*(w)^2)
plt.plot(log(w),log(y));
Okay so now I have to do one more plot but its a little bit more complicated.
w = np.arange(1e3, 1e7, 1e3)
z = 1/ (((5.89824e-15 (w ** 4))+(1-2.56e-8 (w ** 2))) ** 0.5)
b = plt.loglog(w, z);
This give me an error:
z = 1/ (((5.89824e-15 (w ** 4))+(1-2.56e-8 (w ** 2))) ** 0.5)
TypeError: 'float' object is not callable
Never mind I fixed it.
You can use the numpy.arange function to get a numpy version of range. A reasonable range for this function is:
w = np.arange(1e3, 1e7, 1e3)
(That is, going from 1000 to 10000000 in steps of 1000). However, note that in order to make Python know you're trying to use exponentiation rather than the bitwise xor operator, you should change your line to:
y = 1/(1+2.56e-8*(w ** 2))
Then, if you make a log-log plot, you end up with:
plt.loglog(w, y)

Categories