I'm trying to implement the SOR algorithm in Python 3.X in order to solve an electrostatics problem. But, when inside the while loop, the break condition (relative error between previous and current iteration) appears to be fulfilled in the first iteration, which is certainly not correct. When troubleshooting the problem I found that the previous and current iterations have matching values:
def solve_laplace_SOR(w,tolerance,cant_puntos,step,volt):
phi_vec=np.zeros(cant_puntos)# zero seed vector, stores previous iteration
phi_vec_k1=np.zeros(cant_puntos) #Stores current iteration
b_vec=load_ind_term(volt,cant_puntos) #independent term
E_vec=np.zeros(cant_puntos) #Electric field
R_error=100 #Initializes relative error condition so as to enter the loop
i=0 #counts iterations made
#Initializes boundary conditions
phi_vec_k1[0]=volt/2
phi_vec_k1[cant_puntos-1]=-volt/2
while R_error > tolerance:
phi_vec=phi_vec_k1[:] #Stores previous value as a copy, I checked this using id() function
phi_vec_k1[1]=((b_vec[0]-phi_vec[2])/(-2)-phi_vec[1])*w+phi_vec[1]
for x in range(2,cant_puntos-3):
phi_vec_k1[x]=((b_vec[x-1]-phi_vec[x+1]-phi_vec_k1[x-1])/(-2)-phi_vec[x])*w+phi_vec[x]
E_vec[x]=(-(phi_vec_k1[x+1]-phi_vec_k1[x-1])/(2*step))
pass
phi_vec_k1[cant_puntos-2]=((b_vec[cant_puntos-2]-phi_vec_k1[cant_puntos-3])/(-2)- phi_vec[cant_puntos-2])*w+phi_vec[cant_puntos-2]
E_vec[cant_puntos-2]=(-(phi_vec_k1[cant_puntos-1]-phi_vec_k1[cant_puntos-3])/(2*step))
E_vec[1]=(-(phi_vec_k1[2]-phi_vec_k1[0])/(2*step))
R_error=np.linalg.norm(np.array(phi_vec_k1)-np.array(phi_vec),1)/np.linalg.norm(phi_vec_k1,1)
i+=1
print(phi_vec_k1) #This outputs the same values
print(phi_vec)
pass
return E_vec
When setting an always true break condition, the function converges to expected values. Since i'm new to python and programming in general, i can't seem to find the reason for the unwanted update. I really hope you can, thanks very much!
Related
Let's say I have a set of variables ${x{1},...,x{n}}$ and a randomly given, but fixed number $s$. How to find the minimum number of variables required to sum up to that fixed number? We can presume, that the variables always sum up to the given number. So far I have achieved this:
def poss(x,s):
if s<=0:
if s==0:
return 1
if s<0:
return -1
else:
for i in x:
if poss(x,s-i)==1:
print("right")
if poss(x,s-i)==-1:
print("wrong")
else:
pass
I know at some point I need to possibly create an array that keeps track of how many addings each branch has made and delete those that don't work, then take minimum of that, but I'm not sure where or how.
an example of output I calculated by hand:
print(poss([2,3],10)) --> output is 4
It's important to note that when you use recursion inside for loops, all variables stored inside each recursion will be lost when exiting the recursion. To solve this we can capture the count of recursions (ie. the number of x elements used to reduce s) in a global variable, lets call memory.
Next we need to do three things:
The only instance in which memory should be changed is if s==0.
Memory count should only be changed when s==0 from the minimum number of subtractions. (we can sort x from largest to smallest so that we start cutting s with the bigger values first. Example: x=[1,1,4], s=8 should output 2 since (s-4-4 = 0), not 8 (s-1-1-1-1-1-1-1-1 = 0) where every subtraction is a new recursion)
We also need to make sure memory is only ever changed once (otherwise other combinations of elements in x will update it). To do this we can check the the value of memory prior to each following recursion and abort if memory has already been found.
The final code:
memory = 0
def poss2(x, s, count=0):
big_to_small = sorted(x, reverse=True)
global memory # Call on global variable
if s==0: # Capture count in global variable. Recursion inside of for loops will lose all previous data.
memory=count
elif s<0:
return count-1 # Go back, S too small
else:
for i in big_to_small:
if memory==0: # If memory is till zero, s==0 was not yet achieved. Keep recursing with new s and count
poss2(big_to_small, s-i, count+1)
return memory # Return the captured memory
poss2([1,1,1,6], 12)
# 2 --> (6,6)
poss2([2,3], 10)
# 4 --> (3,3,2,2)
poss2([2,7,5,1,6,32], 100)
# 5 --> (32, 32, 32, 2, 2)
Note also, this method is somewhat slow since it will iterate over every value in the for loop and do so in every recursion. A better approach to the same problem would be using something like
count = s // max(i)
s = s - count*max(i)
and then working your way down from the highest i in x.
Cheers!
I am entering a while loop with a specific initial condition (m=0). Inside the while loop I have a for loop which needs to break if a spec. condition is reached, here if my growth rate is >= 20%.
If this condition is reached I want to leave the for loop and use i to set the new m. Then I want to do a new for loop and again leave the loop if the condition is reached and use the new i for m.
I tried with m+=i but this sums up the i's, which I don't want. I want the every new i is used for m. Please find below the code
nvdia=pd.read_csv(r"/NVDA.csv",sep=",").round(1)
nvdia["Date"]=pd.to_datetime(nvdia["Date"])
nvdia=nvdia.set_index(nvdia["Date"])
nvdia=nvdia.drop("Date",1)
nvdia=nvdia.loc["2017-07-01":"2018-07-01"]
#nvdia["Close"].plot()
m=0
i=0
while m<len(nvdia.index):
m+=i ###This is what I use but it is wrong. If I use i=m the loop is goes infinity, which really is strange
for i in range(m,len(nvdia.index)):
percentage_growth=100*(nvdia["Close"].values[i]/nvdia["Close"].values[m]-1)
if percentage_growth>=20:
break
#zmf: Thank you it helped. However I needed to add an additional break statement to leave the while loop, since my condition m
In case someone might have one day same/similar issue, here is the solution
m=0
while m<=len(nvidia.index):
for i in range(m,len(nvidia.index)):
percentage_growth=100*(nvidia["Close"].values[i]/nvidia["Close"].values[m]-1)
if percentage_growth>=20:
m=i
print(m,percentage_growth)
break
else:
percentage_growth=100*(nvidia["Close"].values[i]/nvidia["Close"].values[m]-1)
if i+1==len(nvidia.index):
break
I am new in python and I am trying to learn it by myself. I am currently working on a code, which gives me index error because somehow for loop does not populate my data. I am supposed to iterate a value and with it, I depend on the previous value to produce the new value. Normally this was easy with matlab, only with x(:,k) but python does not work the same way and I will really be grateful for any help that does not judge my level of knowledge in python. Here how it goes:
x = np.matrix([[1.2],[.2]]) # prior knowledge
A = np.matrix([[1, 1], [0, 1]])
B = np.matrix([[.5], [1]])
U = -9
t1 = range(1,100,1)
for k, val in enumerate(t1):
x[:,k] = A*x[:,k-1] + B*U
To my understanding, the error 'IndexError: index 1 is out of bounds for axis 1 with size 1' pops up because the for loop does not populate the data 'x' and therefore, there is no value for neither 'k-1' nor 'k'.
What I should do is to iterate and store 'x' values and pick the relevant previous value each time to obtain new value with given equation till the end of loop. As you can see, I have a column matrix and I should have a column matrix each time. I hope I could make myself clear.
Thank you
The first line is the initial value of x, the second, third, fourth and fifth lines are the values that are used in for loop to calculate iterations for x.
What I am trying to implement is code for kaman filter in general. In this system, the current value x(k) is calculated with previous value x(k-1) with given equation x(k) = Ax(k-1) + BU. Each x(k) value becomes x(k-1) in next iteration until loop is executed. Here, I am expecting to have (2,k) matrix after every loop because record of values are essential for other calculations. And to use the previous value in current value, I need to access to (k-1)th value.
The question was solved by juanpa.arrivillaga (https://stackoverflow.com/users/5014455/juanpa-arrivillaga) Thank you.
Please look at following while loop code written in Python:
x=25
epsilon=0.01
high=max(1.0,x)
low=0.0
*ans=(low+high)/2.0*
while abs(ans**2-x)>=epsilon:
if ans2>x:
high=ans
else:
low=ans
*ans = (high + low)/2.0*
print("ans:",ans,)
This is a guess loop (exhaustion), it should find the approx for square root of a positive number within the margin error on 0,01.
But I cant understand why we must define ans (ans=(low+high)/2.0) the second time, first before the loop and then again in the loop. Could someone tell me what purpose the second definition have since im seeing the first one being enough?
Thanks
Arif
It's because you need to perform that calculation on each iteration of the loop including the very first iteration. Since your while test is the very first part of the loop, you need to do it once before the loop starts.
Here's a way to do it with just one statement:
while True:
*ans = (high + low)/2.0*
if abs(ans**2-x)>=epsilon:
break
if ans2>x:
high=ans
else:
low=ans
I am new to Python and I'm writing a program to compute the resultants of distributed forces.
My method works like this:
force =[1,2,3,4,5]
distance =[2,3,4,5,6]
The idea is to break any section of a distributed force into 2 triangles whose area can be found using:
lowerarea = ((distance[i+1] - distance[i]) *force[i]) * 0.5
upperarea = ((distance[i+1] - distance[i]) *force[i+1]) * 0.5
This is my for loop to find the lower areas:
for i in range(0,len(force)):
lowerarea= (dist[i+1]-dist[i])*force[i]*0.5
print (f)
i = i+1
I obviously get the error that the index is out of bounds since d[6] doesn't exist how do i stop the loop once d[5] is evaluated?
Also how do i save the output of the loop f to a new variable?
Thanks!
The problem with the index going out of bounds is because you're doing an additional increment with i = i+1. Remove that line, because the loop is already doing that increment for you. By having it in there, you're pushing the value of i beyond len(force) - 1 (which as the other folks already pointed out is the highest index of these arrays).
As to f, you're not using or changing it at all during the loop, so why print it or try to store its value? The value isn't going to change anywhere in this code.
Why not create a new list?
results = []
for (...):
results.append(f)
Your out-of-range error is due to the fact that len(force) == 6 -- you want len(force) - 1.