Why does this code take so long to be executed? - Python - python

I coded this on Python. It took way too long to finish if the input were just 40x40 (it's for image processing using numpy). Its behavious is the following: there's an array with objects in it (which have an 'image' attribute which is a numpy array) and then I check if that object is somewhere in another array, and then take the next from the first array and repeat the process until I've checked if all are in the other array:
#__sub_images is the array containing the objects to be compared
#to_compare_image is the image that is received as parameter to check if the objects are in there.
#get_sub_images() is just to retrieve the objects from the array from the received array to find.
#get_image() is the method that retrieves the attribute from the objects
same = True
rows_pixels = 40 #problem size
cols_pixels = 40 #problem size
i = 0 #row index to move the array containing the object that must be checked if exist
j = 0 #col index to move the array containing the object that must be checked if exist
k = 0 #row index to move the array where will be checked if the object exist
l = 0 #col index to move the array where will be checked if the object exist
while i < len(self.__sub_images) and k < len(to_compare_image.get_sub_images()) and l < len(to_compare_image.get_sub_images()[0]):
if not np.array_equal(self.__sub_images[i][j].get_image(), to_compare_image.get_sub_images()[k][l].get_image()):
same = False
else:
same = True
k = 0
l = 0
if j == len(self.__sub_images[0]) - 1:
j = 0
i += 1
else:
j += 1
if not same:
if l == len(to_compare_image.get_sub_images()[0]) - 1:
l = 0
k += 1
else:
l += 1
I managed to code it with just a while, instead of 4 for-loops which is what I used to do before. Why is it taking so long still? Is it normal or is there something wrong? The complexity is supposed to be x and not x⁴
The code that is not included are just getters, I hope you can understand it with the #notes at the begining.
THanks.

Instead of this:
if not np.array_equal(self.__sub_images[i][j].get_image(), to_compare_image.get_sub_images()[k][l].get_image()):
same = False
else:
same = True
#snip
if not same:
#snip
You can do this:
same=np.array_equal(self.__sub_images[i][j].get_image(), to_compare_image.get_sub_images()[k][l].get_image())
if same:
#snip
else:
#snip
This uses less if-branches than before.

Related

I want to create a list of lists

I know there is quite a number of similar questions on stackoverflow but they don't seem to be solving my problem. If you look at my code below, you can see that I am creating a temp list of ads called "tempAdList" and when the if condition evaluate true I am creating a list of lists called "ad_list". I am appending to "ad_list" so I am expecting that everytime the "if statement" evaluates true a new list of 4 ads is appended to "ad_list" but for whatever reason I am getting below output which is not what i am looking for. what am I doing wrong here?
ads = Advert.objects.all()
counter = 1
tempAdList = []
ad_list = []
for i, ad in enumerate(ads):
tempAdList.append(ad)
if counter == 4:
# print(tempAdList)
ad_list.append(tempAdList)
print(ad_list)
tempAdList.clear()
counter = 0
counter += 1
adsNum = len(ads)
# print("i = {} and adsNum = {}".format(i, adsNum))
if i == adsNum -1 and adsNum % 4 != 0:
ad_list.append(tempAdList)
output:
Using the clear-method on a list also affects all references to it, e.g.
>>a = [1, 2, 3]
>>b = a
>>a.clear()
>>print('a =',a)
a = []
>>print('b =',b)
b = []
So what you are doing in ad_list.append(tempAdList) is to repeatedly add references to the same object to ad_list, i.e. each time you update tempAdList, the same update is done for each of those references. What you really want to do is reset tempAdList with a new object, so replace tempAdList.clear() with tempAdList=[].
If you just want a list of lists, where inner lists are having 4 elements.
You can try something like :
new_list = [ads[i:i+4] for i in range(0, len(ads), 4)]
Every time you do tempAdlist.clear(), you cleared all elements of the list. But because you appended the list to ad_list, you basically cleared it there too. so you have one less list. This is because of the nature of lists being referenced instead of recreated. What you want is to create a list from tempAdlist when appending, like so: ad_list.append(list(tempAdlist)) this way it will be a whole new list from the tempAdlist. Essentially your code becomes:
ads = Advert.objects.all()
counter = 1
tempAdList = []
ad_list = []
for i, ad in enumerate(ads):
tempAdList.append(ad)
if counter == 4:
# print(tempAdList)
ad_list.append(list(tempAdList))
print(ad_list)
tempAdList.clear()
counter = 0
counter += 1
adsNum = len(ads)
# print("i = {} and adsNum = {}".format(i, adsNum))
if i == adsNum -1 and adsNum % 4 != 0:
ad_list.append(list(tempAdList))

Issues with using np.linalg.solve in Python

Below, I'm trying to code a Crank-Nicholson numerical solution to the Navier-Stokes equation for momentum (simplified with placeholders for time being), but am having issues with solving for umat[timecount,:], and keep getting the error "ValueError: setting an array element with a sequence". I'm extremely new to Python, does anyone know what I could do differently to avoid this problem?
Thanks!!
def step(timesteps,dn,dt,Numvpts,Cd,g,alpha,Sl,gamma,theta_L,umat):
for timecount in range(0, timesteps+1):
if timecount == 0:
umat[timecount,:] = 0
else:
Km = 1 #placeholder for eddy viscosity
thetaM = 278.15 #placeholder for theta_m for time being
A = Km*dt/(2*(dn**2))
B = (-g*dt/theta_L)*thetaM*np.sin(alpha)
C = -dt*(1/(2*Sl) + Cd)
W_arr = np.zeros(Numvpts+1)
D = np.zeros(Numvpts+1)
for x in (0,Numvpts): #creating the vertical veocity term
if x==0:
W_arr[x] = 0
D[x] = 0
else:
W_arr[x] = W_arr[x-1] - (dn/Sl)*umat[timecount-1,x-1]
D = W_arr/(4*dn)
coef_mat_u = Neumann_mat(Numvpts,D-A,(1+2*A),-(A+D))
b_arr_u = np.zeros(Numvpts+1) #the array of known quantities
umat_forward = umat[timecount-1,2:Numvpts]
umat_center = umat[timecount-1,1:Numvpts-1]
umat_backward = umat[timecount-1,0:Numvpts-2]
b_arr_u = np.zeros(Numvpts+1)
for j in (0,Numvpts):
if j==0:
b_arr_u[j] = 0
elif j==Numvpts:
b_arr_u[j] = 0
else:
b_arr_u[j] = (A+D[j])*umat_backward[j]*(1-2*A)*umat_center[j] + (A-D[j])*umat_forward[j] - C*(umat_center[j]*umat_center[j]) - B
umat[timecount,:] = np.linalg.solve(coef_mat_u,b_arr_u)
return(umat)
Please note that,
for i in (0, 20):
print(i),
will give result 0 20 not 0 1 2 3 4 ... 20
So you have to use the range() function
for i in range(0, 20 + 1):
print(i),
to get 0 1 2 3 4 ... 20
I have not gone through your code rigorously, but I think the problem is in your two inner for loops:
for x in (0,Numvpts): #creating the vertical veocity term
which is setting values only at zero th and (Numvpts-1) th index. I think you must use
for x in range(0,Numvpts):
Similar is the case in (range() must be used):
for j in (0,Numvpts):
Also, here j never becomes == Numvpts, but you are checking the condition? I guess it must be == Numvpts-1
And also the else condition is called for every index other than 0? So in your code the right hand side vector has same numbers from index 1 onwards!
I think the fundamental problem is that you are not using range(). Also it is a good idea to solve the NS eqns for a small grid and manually check the A and b matrix to see whether they are being set correctly.

2d list not working

I am trying to create a 2D list, and I keep getting the same error "TypeError: list indices must be integers, not tuple" I do not understand why, or how to use a 2D list correctly.
Total = 0
server = xmlrpclib.Server(url);
mainview = server.download_list("", "main")
info = [[]]
info[0,0] = hostname
info[0,1] = time
info[0,2] = complete
info[0,3] = Errors
for t in mainview:
Total += 1
print server.d.get_hash(t)
info[Total, 0] = server.d.get_hash(t)
info[Total, 1] = server.d.get_name(t)
info[Total, 2] = server.d.complete(t)
info[Total, 3] = server.d.message(t)
if server.d.complete(t) == 1:
Complete += 1
else:
Incomplete += 1
if (str(server.d.message(t)).__len__() >= 3):
Error += 1
info[0,2] = Complete
info[0,3] = Error
everything works, except for trying to deal with info.
Your mistake is in accessing the 2D-list, modify:
info[0,0] = hostname
info[0,1] = time
info[0,2] = complete
info[0,3] = Errors
to:
info[0].append(hostname)
info[0].append(time)
info[0].append(complete)
info[0].append(Errors)
Same goes to info[Total, 0] and etc.
The way you created info, it is a list containing only one element, namely an empty list. When working with lists, you have to address the nested items like
info[0][0] = hostname
For initialization, you have to create a list of lists by e.g.
# create list of lists of 0, size is 10x10
info = [[0]*10 for i in range(10)]
When using numpy arrays, you can address the elements as you did.
One advantage of "lists of lists" is that not all entries of the "2D list" shall have the same data type!
info = [[] for i in range(4)] # create 4 empty lists inside a list
info[0][0].append(hostname)
info[0][1].append(time)
info[0][2].append(complete)
info[0][3].append(Errors)
You need to create the 2d array first.

How can I access the integer held in a variable which is defined by a separate definition

Current section I'm working on requires me to take coloured pieces from the bar and place them onto a board.
I've had to define the board through makeBoard and the values are stored in "myBoard"
What I'm struggling with is that on my next section "enterPiece" I've got it so I successfully take the relevant coloured pieces from the bar, detract it from the number and then allocate the piece to the board..
what I'm aiming to do is.. 0 < aPoint <= n (where n is the size of the board where I've defined in makeBoard), but I don't know how to get python to get the n from the variable myBoard
def enterPiece(aBoard, aColour, aPoint):
c = aBoard
if 0 < aPoint:
for j in range(aPoint):
c.removePieceFromPoint(aColour, 0)
c.addPieceToPoint(aColour, aPoint)
return True
else:
return False
it looks like n is Board.size, so you should be able to rewrite as:
def enterPiece(aBoard, aColour, aPoint):
c = aBoard
if 0 < aPoint <= aBoard.size:
for j in range(aPoint):
c.removePieceFromPoint(aColour, 0)
c.addPieceToPoint(aColour, aPoint)
return True
else:
return False

"shape mismatch" error using numpy in python

I am trying to generate a random array of 0s and 1s, and I am getting the error: shape mismatch: objects cannot be broadcast to a single shape. The error seems to be occurring in the line randints = np.random.binomial(1,p,(n,n)). Here is the function:
import numpy as np
def rand(n,p):
'''Generates a random array subject to parameters p and N.'''
# Create an array using a random binomial with one trial and specified
# parameters.
randints = np.random.binomial(1,p,(n,n))
# Use nested while loops to go through each element of the array
# and assign True to 1 and False to 0.
i = 0
j = 0
rand = np.empty(shape = (n,n),dtype = bool)
while i < n:
while j < n:
if randints[i][j] == 0:
rand[i][j] = False
if randints[i][j] == 1:
rand[i][j] = True
j = j+1
i = i +1
j = 0
# Return the new array.
return rand
print rand
When I run it by itself, it returns <function rand at 0x1d00170>. What does this mean? How should I convert it to an array that can be worked with in other functions?
You needn't go through all of that,
randints = np.random.binomial(1,p,(n,n))
produces your array of 0 and 1 values,
rand_true_false = randints == 1
will produce another array, just with the 1s replaced with True and 0s with False.
Obviously, the answer by #danodonovan is the most Pythonic, but if you really want something more similar to your looping code. Here is an example that fixes the name conflicts and loops more simply.
import numpy as np
def my_rand(n,p):
'''Generates a random array subject to parameters p and N.'''
# Create an array using a random binomial with one trial and specified
# parameters.
randInts = np.random.binomial(1,p,(n,n))
# Use nested while loops to go through each element of the array
# and assign True to 1 and False to 0.
randBool = np.empty(shape = (n,n),dtype = bool)
for i in range(n):
for j in range(n):
if randInts[i][j] == 0:
randBool[i][j] = False
else:
randBool[i][j] = True
return randBool
newRand = my_rand(5,0.3)
print(newRand)

Categories

Resources