Setting numpy array values to be more precise - python

I have an array which has values, if calcualted precisely: [3.056565 3.924560] however in python it prints rounded numbers and the array is [3.06, 3.93]. The array is the used to calculate something else and the result is different than expected. How can I make that array to stop rounding itself?
Here is the code where you can see that array is not precisely calcualted:
import datetime
import math
import numpy as np
def numGradient(f, x, h):
n = len(x)
g = [0]*n
g = np.array(g)
for i in range(n):
e = [0]*n
e[i] = 1
e=np.array(e)
g[i] = (f(x+e*h)-f(x-e*h))//(2*h)
return(g)
def myFun(x) :
return ( 0.6 + ((math.sin(x[0]**2-x[1]**2))**2-0.5)/((1+0.001*(x[0]**2+x[1]**2))**2) )
x_old=(3,4)
xthis = x_old - 0.01*numGradient(myFun, x_old, 10**(-6))
print(xthis)

There are several issues with your code. It probably does not compute what you expect it to compute.
First, this is the wrong way to initialize a NumPy array
g = [0]*n
g = np.array(g)
Replace it with
g = np.zeros(n)
Second, do the same with e.
for i in range(n):
e = np.zeros(n)
e[i] = 1
And most importantly replace
g[i] = (f(x+e*h)-f(x-e*h))//(2*h)
with
g[i] = (f(x+e*h)-f(x-e*h))/(2*h)
This is floating point division after all. And // is the so-called integer division in Python 3.
After the changes you will get
[ 3.056565 3.92456 ]
Which is probably what you should be getting.
Here is the complete code after the changes:
import datetime
import math
import numpy as np
def numGradient(f, x, h):
n = len(x)
g = np.zeros(n)
for i in range(n):
e = np.zeros(n)
e[i] = 1
g[i] = (f(x+e*h)-f(x-e*h))/(2*h)
return(g)
def myFun(x) :
return ( 0.6 +
((math.sin(x[0]**2-x[1]**2))**2-0.5)/((1+0.001*(x[0]**2+x[1]**2))**2) )
x_old=(3,4)
np.set_printoptions(precision=6)
xthis = x_old - 0.01*numGradient(myFun, x_old, 10**(-6))
print(xthis)

Related

Issue specifying datatype for the Mandelbrot set

I have optimized a bit on calculating the Mandelbrot set, & I now wish to be able to specify whether my arrays should be float64 or float32 instead of the easier implementation with type complex128 or complex64. I use the fact that for a complex number (a+jb)^2 = a^2-b^2 + (2ab)j, but this seems to give me a slightly different wrong mandelbrot set. The code is seen below:
from timeit import default_timer as timer
import numpy as np
from numexpr import evaluate
import matplotlib.pyplot as plt
#%% Inputs
N = 5000
I = 20
T = 2 #Thresholdenter code here
#%% Functions
def mandel_brot_vector(I,C,T,datatype):
Cre = np.array(C.real,dtype=datatype)
Cim = np.array(C.imag,dtype=datatype)
M = np.zeros(Cre.shape,dtype=datatype)
zreal=0
zimag=0
for i in range(I):
M[zreal*zreal+zimag*zimag<T**2] = i/I
zreal = evaluate("zreal*zreal-zimag*zimag+Cre") #complex multiplication rule
zimag = evaluate("2*zreal*zimag+Cim") #complex multiplication rule
N = len(M[0])
M = np.reshape(np.array(M),(N//2,N)).astype(datatype)
M = np.concatenate((M,M[::-1]),axis=0)
return M
def create_C(N,split):
C_re = np.linspace(np.full((1,N),-2)[0],np.full((1,N),1)[0],N).T
C_im = np.linspace(np.full((1,N),1.5*1j)[0],np.full((1,N),-1.5*1j)[0],N)
C = C_re+C_im
C = C[:N//2,:]
if split != 0:
C_split = np.array_split(C,split)
else:
C_split = C
return np.array(C_split)
C = create_C(N, 0)
t0_32 = timer()
M32 = mandel_brot_vector(I,C,T,np.float32)
t_32 = timer() - t0_32
t0_64 = timer()
M64 = mandel_brot_vector(I,C,T,np.float64)
t_64 = timer() - t0_64
plt.matshow(M64,cmap="hot")
print(" "*10,f"N={N}")
print(f"{'Float 32':<20}{t_32:<40}",
f"\n{'Float 64':<20}{t_64:<40}"
)
Currently the image I get: wrong mandelbrot. For reference, the following function will produce the correct mandelbrot set but with complex128:
def mandel_brot(I,C,T):
M = np.zeros(C.shape)
z=0
for i in range(I):
M[np.abs(z)<T] = i/I
z = evaluate("z*z+C")
N = len(M[0])
M = np.reshape(np.array(M),(N//2,N)).astype(datatype)
M = np.concatenate((M,M[::-1]),axis=0)
return M
Hope someone can help solve this issue, thanks in advance. Btw do not bother with the split of the C array, it is set up to run with multiprocessing which I am not using in the code attached.

python : simulate an array with different length

See the code. I am trying to simulate an array called 'xx'. Following the code, I am simulating each component in the matrix one by one. This is super time-consuming when M and N are very large. The reason why I do this is because in the function 'func', for each column data, the 'samplesize 'is different. Is there any faster way to generate this numpy array please? Thank you.
import numpy as np
def func ( x , n):
samplesize = np.random.poisson(x)
return np.random.uniform(0, 2, samplesize)
def singlerow(x, n ,N):
rowdata = np.zeros(N)
rowdata[0] = 0
for i in range(1, N):
rowdata[i] = rowdata[i-1] + np.sum(func(x, n))
return rowdata
def simulatematrix( x,n ,M, N):
result = np.zeros((M,N))
for m in range(M):
result[m] = singlerow(x,n, N)
return result
M = 100
N = 10
xx = simulatematrix(40, 10, M, N)

Gauss seidel Implementation in python

import numpy as np
from scipy.linalg import solve_triangular as triSolve
#O(n) per iteration, so overall O(nN), good for large SPD/SDD matrices
def GS_iter(A, b, N):
m = len(A)
L = np.tril(A)
P = L-A
print(P)
x = np.zeros(m)
print(x)
for k in range(N):
x = triSolve(L,b+P#x, True)
return x
#examples
A = np.array([[10,2,3,1],[1,10,0,1],[0.2,1,10,2],[0.1,3,3,10]])
b = np.array([1,2,1,0])
x = GS_iter(A,b,50000)
ans = A#x-b
print(ans)
print(np.linalg.norm(ans))
Above is my Gauss-Seidel method in Python. For some reason it is not converging even after 50000 iterations to the solution even when the matrix A is strict diagonal dominant. Below is the same implementation in MATLAB which works:
function x = gSeidel(A,B,N)
[n,~] = size(A);
L = tril(A);
P = L-A; %P = -U
x = zeros(n,1); %x_0
for k = 1:N
x = L\(B+P*x);
end
end
What mistakes did I make? I think it is in TriSolve method since if I replaced it with regular LU solver such as (np.linalg.solve) it works. Why doesn't triangular solve behave as intended here?
the lower argument is the fourth
replace your line by x = triSolve(L,b+P#x, lower=True)
Signature:
triSolve(
a,
b,
trans=0,
lower=False,
unit_diagonal=False,
overwrite_b=False,
debug=None,
check_finite=True,
)

Error using scicpy.integrate.odeint and sympy symbols

I'm trying to solve the following system: d²i/dt² + R'(i)/L di/dt + 1/LC i(t) = 1/L dE/dt as a set of coupled first order differential equations:
di/dt = k
dk/dt = 1/L dE/dt - R'(i)/L k - 1/LC i(t)
Here is the code I'm using:
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from scipy.integrate import odeint
#Define model: x = [i , k]
def RLC(x , t):
i = sp.Symbol('i')
t = sp.Symbol('t')
#Data:
E = sp.ln(t + 1)
dE_dt = E.diff(t)
R1 = 1000 #1 kOhm
R2 = 100 #100 Ohm
R = R1 * i + R2 * i**3
dR_di = R.diff(i)
i = x[0]
k = x[1]
L = 10e-3 #10 mHy
C = 1.56e-6 #1.56 uF
#Model
di_dt = k
dk_dt = 1/L * dE_dt - dR_di/L * k - 1/(L*C) * i
dx_dt = np.array([di_dt , dk_dt])
return dx_dt
#init cond:
x0 = np.array([0 , 0])
#time points:
time = np.linspace(0, 30, 1000)
#solve ODE:
x = odeint(RLC, x0, time)
i = x[: , 0]
However, I get the following error: TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'
So, I don't know if sympy and odeint don't work well together. Or maybe is it a problem because I defined t as sp.Symbol?
When you differentiate a function, you get a function back. So you need to evaluate it at a point in order to get a number. To evaluate a sympy expression, you could use .subs() but I prefer .replace() which feels more powerful (at least for me).
You must try and make every single variable have its own name in order to avoid confusion. For example, you replace the float input t with a sympy Symbol from the very beginning, thus losing the value of t. The variables x and i are also repeated in the outer scope which is not good practice if they mean different things.
The following should avoid confusion and hopefully produce something that you were expecting:
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# Define model: x = [i , k]
def RLC(x, t):
# define constants first
i = x[0]
k = x[1]
L = 10e-3 # 10 mHy
C = 1.56e-6 # 1.56 uF
R1 = 1000 # 1 kOhm
R2 = 100 # 100 Ohm
# define symbols (used to find derivatives)
i_symbol = sp.Symbol('i')
t_symbol = sp.Symbol('t')
# Data (differentiate and evaluate)
E = sp.ln(t_symbol + 1)
dE_dt = E.diff(t_symbol).replace(t_symbol, t)
R = R1 * i_symbol + R2 * i_symbol ** 3
dR_di = R.diff(i_symbol).replace(i_symbol, i)
# nothing should contain symbols from here onwards
# variables can however contain sympy expressions
# Model (convert sympy expressions to floats)
di_dt = float(k)
dk_dt = float(1 / L * dE_dt - dR_di / L * k - 1 / (L * C) * i)
dx_dt = np.array([di_dt, dk_dt])
return dx_dt
# init cond:
x0 = np.array([0, 0])
# time points:
time = np.linspace(0, 30, 1000)
# solve ODE:
solution = odeint(RLC, x0, time)
result = solution[:, 0]
print(result)
Just something to note: the value i = x[0] seemed to sit very close to 0 throughout each iteration. This means dR_di stayed basically at 1000 the whole time. I'm not familiar with odeint or your specific ODE, but hopefully this phenomenon is expected and isn't a problem.

using trapezoidal numerical integration in python

I need to integrate this function using trapezoidal rule in python:
theta = .518/r^2 * dr/(sqrt(2*1.158 + 2/r - .518^2/2r^2))
I have written my code and I should be seeing an ellipsoidal structure when plotted. theta should run from 0 to 2pi and r_min = .16 & r_max = .702
import numpy as np
import matplotlib.pyplot as plt
def trapezoidal(f, a, b, n):
h = float(b-a)/n
result = 0.5*f(a) + 0.5*f(b)
for i in range(1, n):
result += f(a + i*h)
result *= h
return result
intg =[]
v = lambda r: (0.5108/(r**2))* (1./np.sqrt(2*1.158+(2/r)-.5108**2/(2*r**2)))
n = np.arange(1,1000,100)
theta = np.arange(0,2*np.pi,100)
for j in n:
numerical = trapezoidal(v, .16,.702 , j)
intg.append(numerical)
plt.plot(numerical,theta)
plt.show()
I am doing some very elementary mistake I guess, because I am getting no plot out of it. I think the trapezoidal routine is correct, because it worked for other functions. your help is very appreciated
Alternatively, you could use quadpy (a project of mine).
import numpy as np
import quadpy
val = quadpy.line_segment.integrate_split(
lambda r: 0.5108/r**2 / np.sqrt(2*1.158 + 2/r - 0.5108**2/(2*r**2)),
0.15, 0.702, 100,
quadpy.line_segment.Trapezoidal()
)
print(val)
gives 0.96194633532. The trapezoidal formula is mostly implemented for historical purposes, however. A better and equally simple rule is quadpy.line_segment.Midpoint. An even better approach is certainly adaptive quadrature
val, error_estimate = quadpy.line_segment.integrate_adaptive(
lambda r: 0.5108/r**2 / np.sqrt(2*1.158 + 2/r - 0.5108**2/(2*r**2)),
[0.15, 0.702],
1.0e-10
)
print(val)
which gives the more accurate 0.961715309492, or even tanh-sinh quadrature
val, error_estimate = quadpy.line_segment.tanh_sinh(
lambda r: 0.5108/r**2 / np.sqrt(2*1.158 + 2/r - 0.5108**2/(2*r**2)),
0.15, 0.702,
1.0e-30
)
print(val)
which gives 0.9617153094932353183036398697528.
There are a couple of issues here.
First one is that the third argument in np.arrange is not the number of values to be generated but the step. This means that theta will have only one value and that n and thus intg will have 10 instead of 100 values.
Assuming that was your intention (100 values) you can do this
intg =[]
v = lambda r: (0.5108/(r**2))* (1./np.sqrt(2*1.158+(2/r)-.5108**2/(2*r**2)))
n = np.arange(1,1000,10)
theta = np.arange(0,2*np.pi,2*np.pi/100)
#print theta
for j in n:
numerical = trapezoidal(v, .16,.702 , j)
intg.append(numerical)
Then you're plotting numerical which is basically a single number and what you probably wanted to plot was the integral value intg - to do so you also need to convert intg from a list into np.array:
intg = np.array(intg)
With these changes the program works as intended,
plt.plot(intg,theta)
plt.show()
If you print the lengths of your numerical and theta, you will see that they are empty lists/arrays.
Try the following:
import numpy as np
import matplotlib.pyplot as plt
def trapezoidal(f, a, b, n):
h = float(b-a)/n
result = 0.5*f(a) + 0.5*f(b)
for i in range(1, n):
result += f(a + i*h)
result *= h
return result
intg =[]
v = lambda r: (0.5108/(r**2))* (1./np.sqrt(2*1.158+(2/r)-.5108**2 /(2*r**2)))
n = np.arange(1, 1001)
theta = np.linspace(0,2.*np.pi,1000)
for j in n:
numerical = trapezoidal(v, .16,.702 , j)
intg.append(numerical)
plt.plot(intg,theta)
plt.show()

Categories