def jacobi(m,numiter=100):
#Number of rows determins the number of variables
numvars = m.shape[0]
#construct array for final iterations
history = np.zeros((numvars,numiter))
i = 1
while(i < numiter): #Loop for numiter
for v in range(numvars): # Loop over all variables
current = m[v,numvars] # Start with left hand side (augmented side of matrix)
for col in range(numvars): #Loop over columns
if v != col: # Don't count colume for current variable
current = current - (m[v,col]*history[col, i-1]) #subtract other guesses form previous timestep
current = current/m[v,v] #divide by current variable coefficent
history[v,i] = current #Add this answer to the rest
i = i + 1 #iterate
#plot each variable
for v in range(numvars):
plt.plot(history[v,: i]);
return history[:,i-1]
I have this code that calculates Jacobian method. How do I add a stopping condition for when the solutions converge? i.e. the values for the current iteration have changed less than some threshold e from the values for the previous iteration.
The threshold e will be an input to the function and the default value to 0.00001
You could add another condition to your while loop, so when it reaches your error threshold it stops.
def jacobi(m,numiter=100, error_threshold = 1e-4):
#Number of rows determins the number of variables
numvars = m.shape[0]
#construct array for final iterations
history = np.zeros((numvars,numiter))
i = 1
err = 10*error_threshold
while(i < numiter and err > error_threshold): #Loop for numiter and error threshold
for v in range(numvars): # Loop over all variables
current = m[v,numvars] # Start with left hand side (augmented side of matrix)
for col in range(numvars): #Loop over columns
if v != col: # Don't count colume for current variable
current = current - (m[v,col]*history[col, i-1]) #subtract other guesses form previous timestep
current = current/m[v,v] #divide by current variable coefficent
history[v,i] = current #Add this answer to the rest
#check error here. In this case the maximum error
if i > 1:
err = max((history[:,i] - history[:,i-1])/history[:,i-1])
i = i + 1 #iterate
#plot each variable
for v in range(numvars):
plt.plot(history[v,: i]);
return history[:,i-1]
Related
For some Time, I've written a Needleman Wunsch algorithm for listening to NCBI data streams, but as I've been done with it i knew it could be done better but i by far to stupid to do so. If some of you know what I've done stupid overcomplicated, I would really like to know how to do it better.
At first I want to show you the full code to let you know about the context.
#!/usr/bin/env python
import pandas as pd #to create data frames
from numpy import full #to build the arrays
import subprocess
import os
from itertools import groupby
def needlemanWunsch(lista, listb, rowLen, colLen): #o(n*m)
levensteinTable = full([rowLen, colLen],0)
for j in range(0,colLen): #Fill out the first row
levensteinTable[0, j] = j
for i in range(0,rowLen): #Fill out the first column
levensteinTable[i, 0] = i
for i in range(1,rowLen): #Fill out the rest of the Board in dependency of several cases
for j in range (1,colLen): #traversing with a nested loop
levensteinTable[i,j]=min( #every Levenstein Score has to be the Minimum of three cases
(levensteinTable[i-1, j-1]+(0 if listb[j-1] == lista[i-1] else 1)), #in this part, the Delta of the two strings will be detected
(levensteinTable[i, j-1] +1), #The score of the left cell
(levensteinTable[i-1, j] +1) #The Score of the upper cell
)
return levensteinTable #the finished levenstein Table will be returned
upArrow = "\u2191"
right_arrow = "\u2192"
down_arrow = "\u2193"
leftArrow = "\u2190"
down_right_arrow = "\u2198"
upLeftArrow = "\u2196"
def needlemanWunschTraceBack(listx,listy,rows,columns, gapPenalty = -1, matchBonus = 1, mismatchPenalty = -1): #o(n*m)
#This algorithm will fill out the Penalty Scoreboard and the Arrow Score board
penaltyArray = full([rows, columns],0) #build up the penalty score Array
tracerArray = full([rows, columns],"-") #build up the Array for the traceback arrows
for row in range(rows): #filling the two arrays
for col in range(columns):
if row==0 and col==0: #the first cell
score = 0 #the first Cell doesn't have any alignment
arrow = "-" #no Alignment, no arrow
elif row==0 and col!=0: #the first Row
score = penaltyArray[row, col -1]+gapPenalty #every Cell in this row need his score
arrow = leftArrow #every Arrow in this row has to look up to the start of the array
elif row!=0 and col == 0: #the first column
score = penaltyArray[row-1, col]+gapPenalty #every Cell in this column need his score
arrow = upArrow #every Arrow in this row has to look up to the start of the array
else: #in this case, every other cell will be processed
fromLeftScore = penaltyArray[row,col-1] + gapPenalty #The score of the former left cell + gapPenalty
fromAboveScore = penaltyArray[row-1,col] + gapPenalty #The score of the former Above cell
diagonalLeftCellScore = penaltyArray[row-1,col-1] +(
matchBonus if(listx[row -1]==listy[col-1])else mismatchPenalty
) #if the alighment matches with the former diagonal left cell, it gets a match bonus, else a mismatchPenalty
score = max([fromLeftScore, fromAboveScore, diagonalLeftCellScore]) #The score of our Cell has to be the maximum of the three given scores
arrow =(leftArrow if score==fromLeftScore else upArrow if score==fromAboveScore else\
upLeftArrow if score==diagonalLeftCellScore else 0)
#the right arrow of every cell will be seperately detected
tracerArray[row, col]=arrow #the tracerArray gets the arrows
penaltyArray[row, col]=score #the penaltyArray gets the scores
return tracerArray, penaltyArray
def traceback_alignment(traceback_array,listC,listD,up_arrow = upArrow ,\
left_arrow=leftArrow,up_left_arrow=upLeftArrow,stop="-"): #o(n)
row = len(listC) #The Traceback Algo needs the sequences anyway
col = len(listD)
arrow = traceback_array[row,col] #to get the right arrow for the current position
alignedSeq1 = "" #to initiate the produced alignment upper line
alignedSeq2 = "" #to initiate the produced alignment under line
alignmentIndicator = "" #to indicate the alighment
while arrow != "-": #No Arrow, no interes
arrow = traceback_array[row,col] #the current position in the array inside the loop
print(f"Currently on row: {row} and col: {col}; Arrow: {arrow}") #Because you could get bored without visual process indication
if arrow == up_arrow: #up_arrow shows a gap in under sequence
alignedSeq2 = "-"+alignedSeq2
alignedSeq1 = listC[row-1] + alignedSeq1
alignmentIndicator = " "+alignmentIndicator #to show that here is no alignment
row -=1
elif arrow == up_left_arrow: #up_left_arrow shows that here is accordance between the sequences
alignedSeq1 = listC[row-1] + alignedSeq1
alignedSeq2 = listD[col-1] + alignedSeq2
if listC[row-1] == listD[col-1]:
alignmentIndicator = "|"+alignmentIndicator #visual indicator for accordance
else:
alignmentIndicator = " "+alignmentIndicator #visual indicator for no accordance
row -=1
col -=1
elif arrow == left_arrow:
alignedSeq1 = "-"+alignedSeq1
alignedSeq2 = listD[col-1] + alignedSeq2
alignmentIndicator = " "+alignmentIndicator #visual indicator for no accordance
col -=1
elif arrow == stop:
break
else:
raise ValueError(
f"Traceback array entry at {row},{col}: {arrow}" \
f"is not recognized as an up arrow ({up_arrow}),left_arrow ({left_arrow}), "\
f"up_left_arrow ({up_left_arrow}), or a stop ({stop})."
)
return f"{alignedSeq1}\n{alignmentIndicator}\n{alignedSeq2}"
def seqHandle(seq1, seq2): #to handle a two given Sequences o(n*m)
columnLabels = [label for label in "-"+seq1] #for the later buildet Dataframes
rowLabels = [label for label in "-"+seq2] ##for the later buildet Dataframes
nRows = len("-"+seq1) #Count of all rows
nColumns = len("-"+seq2) #Count of all columns
levensteinBoard = needlemanWunsch(seq1, seq2,nRows,nColumns) #to build the Board with the levensteinDistances
arrowArray, zuchtArray, = needlemanWunschTraceBack(seq1, seq2,nRows, nColumns) #Important for the traceback
levensteinDistance = levensteinBoard[len(seq1)][len(seq2)] #I'll explain the Levenstein Distance in the Readme
return (
f"This is our ScoreBoard with all the important distances\n"\
f"{pd.DataFrame(levensteinBoard, index=columnLabels, columns= rowLabels)}\n"\
f"The Levenstein Distance of{seq1} and {seq2} is {levensteinDistance}.\n"\
f"The trace back arrow board:\n{pd.DataFrame(arrowArray, index=columnLabels, columns= rowLabels)}\n"\
f"The Penalty Score Board:\n{pd.DataFrame(zuchtArray, index=columnLabels, columns= rowLabels)}\n"\
f"{traceback_alignment(arrowArray,seq1,seq2)}"), levensteinDistance
def fileProcessGenerator(fileE): #to iterate over a SequenceSummaryFile o(n)
with open(f'{os.getcwd()}/{fileE}', 'r') as fh: #to savely work with the given file
faiter = (x[1] for x in groupby(fh, lambda line: line[0] ==">")) #to group the single sequences to their related header Line
for header in faiter:
headerStr = header.__next__()[1:].strip() #to fetch the header line from the group
yield (
headerStr.strip().replace('>', '').split()[0], #name of the sequence
''.join(s.strip() for s in faiter.__next__())) #sequence
def FileOfSequencesAnalisis(fileName, OutputPath): #to analyse a SequenceSummaryFile o(n*m*a*b)
print(f"\n\n Warning: I'll proceed really a lot of Sequence combinations Sequences.\n\n This will take Time! Please stay patient")
processnumber = 1 #We want to know, in which process we are
levensteinDistanceCounter= 0 #To count all Levenstein distances so far
LevensteinDistancesAverage = 0 #to calculate the average of all levenstein distances so far
try: #because someone could try shit
for ff in fileProcessGenerator(fileName): #the main loop devines the sequence in the line
for fo in fileProcessGenerator(fileName): #the main loop devines the sequence in the column
if ff != fo: #nobody wants to know the levenstein Distance of two identical sequences
name, seqOne, = ff #to get the important stuff from the generator
namel, seqTwo, = fo
print(
f"processing for {name} and {namel} -Process Nr.{processnumber}\n"\
f"current average Levenstein Distances is {LevensteinDistancesAverage}") #to show, that the process works well
seqHandling, currentLevensteinDistance = seqHandle(seqOne, seqTwo) #to get the struff from seqHandle
with open(f"{OutputPath}/For_{name}_and_{namel}.txt", 'w') as bitch: #to savely save our Output to a file
bitch.write(f"Analysis for {name} and {namel}: \n{seqHandling}")
levensteinDistanceCounter += currentLevensteinDistance
LevensteinDistancesAverage = levensteinDistanceCounter/processnumber
processnumber += 1
except RuntimeError:
print("invalid File. Use a File with inherited fasta Sequences with a Header Line and Sequences")
print(f"I'm done. Here is the average Levenstein Distance of the analysed File:\n{LevensteinDistancesAverage}")
Now I'll show you, what I've been unsatisfied with
def needlemanWunsch(lista, listb, rowLen, colLen): #o(n*m)
levensteinTable = full([rowLen, colLen],0)
for j in range(0,colLen): #Fill out the first row
levensteinTable[0, j] = j
for i in range(0,rowLen): #Fill out the first column
levensteinTable[i, 0] = i
for i in range(1,rowLen): #Fill out the rest of the Board in dependency of several cases
for j in range (1,colLen): #traversing with a nested loop
levensteinTable[i,j]=min( #every Levenstein Score has to be the Minimum of three cases
(levensteinTable[i-1, j-1]+(0 if listb[j-1] == lista[i-1] else 1)), #in this part, the Delta of the two strings will be detected
(levensteinTable[i, j-1] +1), #The score of the left cell
(levensteinTable[i-1, j] +1) #The Score of the upper cell
)
return levensteinTable #the finished levenstein Table will be returned
I've tried to turn every for loop into a comprehension, but somehow there are things I don't know and even don't know for what kind of comprehension I need to search for.
II've tried to turn every for loop into a comprehension, but somehow there are things I don't know and even don't know for what kind of comprehension I need to search for.
from numpy import full #to build the arrays
def needlemanWunsch(lista, listb, rowLen, colLen): #o(n*m)
levensteinTable = full([rowLen, colLen],0)
#for j in range(0,colLen): #Fill out the first row
# levensteinTable[0, j] = j
levensteinTable[0, [j for j in range(0, colLen)]]
#for i in range(0,rowLen): #Fill out the first column
# levensteinTable[i, 0] = i
levensteinTable[[i for i in range(0, rowLen)], 0]
for i in range(1,rowLen): #Fill out the rest of the Board in dependency of several cases
for j in range (1,colLen): #traversing with a nested loop
levensteinTable[i,j]=min( #every Levenstein Score has to be the Minimum of three cases
(levensteinTable[i-1, j-1]+(0 if listb[j-1] == lista[i-1] else 1)), #in this part, the Delta of the two strings will be detected
(levensteinTable[i, j-1] +1), #The score of the left cell
(levensteinTable[i-1, j] +1) #The Score of the upper cell
)
return levensteinTable #the finished levenstein Table will be returned
seq1, seq2= "ATTACA","ATGCT"
nRows, nColumns = len("-"+seq1), len("-"+seq2)
print(needlemanWunsch(seq1, seq2, nRows, nColumns))
but Output of this is like:
[[0 0 0 0 0 0]
[0 0 1 1 1 1]
[0 1 0 1 2 1]
[0 1 1 1 2 2]
[0 0 1 2 2 3]
[0 1 1 2 2 3]
[0 0 1 2 3 3]]
I've trying to implement transition from an amount of space to another which is similar to acceleration and deceleration, except i failed and the only thing that i got from this was this infinite stack of mess, here is a screenshot showing this in action:
you can see a very black circle here, which are in reality something like 100 or 200 circles stacked on top of each other
and i reached this result using this piece of code:
def Place_circles(curve, circle_space, cs, draw=True, screen=None):
curve_acceleration = []
if type(curve) == tuple:
curve_acceleration = curve[1][0]
curve_intensity = curve[1][1]
curve = curve[0]
#print(curve_intensity)
#print(curve_acceleration)
Circle_list = []
idx = [0,0]
for c in reversed(range(0,len(curve))):
for p in reversed(range(0,len(curve[c]))):
user_dist = circle_space[curve_intensity[c]] + curve_acceleration[c] * p
dist = math.sqrt(math.pow(curve[c][p][0] - curve[idx[0]][idx[1]][0],2)+math.pow(curve [c][p][1] - curve[idx[0]][idx[1]][1],2))
if dist > user_dist:
idx = [c,p]
Circle_list.append(circles.circles(round(curve[c][p][0]), round(curve[c][p][1]), cs, draw, screen))
This place circles depending on the intensity (a number between 0 and 2, random) of the current curve, which equal to an amount of space (let's say between 20 and 30 here, 20 being index 0, 30 being index 2 and a number between these 2 being index 1).
This create the stack you see above and isn't what i want, i also came to the conclusion that i cannot use acceleration since the amount of time to move between 2 points depend on the amount of circles i need to click on, knowing that there are multiple circles between each points, but not being able to determine how many lead to me being unable to the the classic acceleration formula.
So I'm running out of options here and ideas on how to transition from an amount of space to another.
any idea?
PS: i scrapped the idea above and switched back to my master branch but the code for this is still available in the branch i created here https://github.com/Mrcubix/Osu-StreamGenerator/tree/acceleration .
So now I'm back with my normal code that don't possess acceleration or deceleration.
TL:DR i can't use acceleration since i don't know the amount of circles that are going to be placed between the 2 points and make the time of travel vary (i need for exemple to click circles at 180 bpm of one circle every 0.333s) so I'm looking for another way to generate gradually changing space.
First, i took my function that was generating the intensity for each curves in [0 ; 2]
Then i scrapped the acceleration formula as it's unusable.
Now i'm using a basic algorithm to determine the maximum amount of circles i can place on a curve.
Now the way my script work is the following:
i first generate a stream (multiple circles that need to be clicked at high bpm)
this way i obtain the length of each curves (or segments) of the polyline.
i generate an intensity for each curve using the following function:
def generate_intensity(Circle_list: list = None, circle_space: int = None, Args: list = None):
curve_intensity = []
if not Args or Args[0] == "NewProfile":
prompt = True
while prompt:
max_duration_intensity = input("Choose the maximum amount of curve the change in intensity will occur for: ")
if max_duration_intensity.isdigit():
max_duration_intensity = int(max_duration_intensity)
prompt = False
prompt = True
while prompt:
intensity_change_odds = input("Choose the odds of occurence for changes in intensity (1-100): ")
if intensity_change_odds.isdigit():
intensity_change_odds = int(intensity_change_odds)
if 0 < intensity_change_odds <= 100:
prompt = False
prompt = True
while prompt:
min_intensity = input("Choose the lowest amount of spacing a circle will have: ")
if min_intensity.isdigit():
min_intensity = float(min_intensity)
if min_intensity < circle_space:
prompt = False
prompt = True
while prompt:
max_intensity = input("Choose the highest amount of spacing a circle will have: ")
if max_intensity.isdigit():
max_intensity = float(max_intensity)
if max_intensity > circle_space:
prompt = False
prompt = True
if Args:
if Args[0] == "NewProfile":
return [max_duration_intensity, intensity_change_odds, min_intensity, max_intensity]
elif Args[0] == "GenMap":
max_duration_intensity = Args[1]
intensity_change_odds = Args[2]
min_intensity = Args[3]
max_intensity = Args[4]
circle_space = ([min_intensity, circle_space, max_intensity] if not Args else [Args[0][3],circle_space,Args[0][4]])
count = 0
for idx, i in enumerate(Circle_list):
if idx == len(Circle_list) - 1:
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
else:
curve_intensity.append(0)
else:
curve_intensity.append(1)
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
count += 1
else:
curve_intensity.append(0)
count += 1
else:
if curve_intensity:
if curve_intensity[-1] == 2 and not count+1 > max_duration_intensity:
curve_intensity.append(2)
count += 1
continue
elif curve_intensity[-1] == 0 and not count+1 > max_duration_intensity:
curve_intensity.append(0)
count += 1
continue
elif count+1 > 2:
curve_intensity.append(1)
count = 0
continue
else:
curve_intensity.append(1)
else:
curve_intensity.append(1)
curve_intensity.reverse()
if curve_intensity.count(curve_intensity[0]) == len(curve_intensity):
print("Intensity didn't change")
return circle_space[1]
print("\n")
return [circle_space, curve_intensity]
with this, i obtain 2 list, one with the spacing i specified, and the second one is the list of randomly generated intensity.
from there i call another function taking into argument the polyline, the previously specified spacings and the generated intensity:
def acceleration_algorithm(polyline, circle_space, curve_intensity):
new_circle_spacing = []
for idx in range(len(polyline)): #repeat 4 times
spacing = []
Length = 0
best_spacing = 0
for p_idx in range(len(polyline[idx])-1): #repeat 1000 times / p_idx in [0 ; 1000]
# Create multiple list containing spacing going from circle_space[curve_intensity[idx-1]] to circle_space[curve_intensity[idx]]
spacing.append(np.linspace(circle_space[curve_intensity[idx]],circle_space[curve_intensity[idx+1]], p_idx).tolist())
# Sum distance to find length of curve
Length += abs(math.sqrt((polyline[idx][p_idx+1][0] - polyline[idx][p_idx][0]) ** 2 + (polyline [idx][p_idx+1][1] - polyline[idx][p_idx][1]) ** 2))
for s in range(len(spacing)): # probably has 1000 list in 1 list
length_left = Length # Make sure to reset length for each iteration
for dist in spacing[s]: # substract the specified int in spacing[s]
length_left -= dist
if length_left > 0:
best_spacing = s
else: # Since length < 0, use previous working index (best_spacing), could also jsut do `s-1`
if spacing[best_spacing] == []:
new_circle_spacing.append([circle_space[1]])
continue
new_circle_spacing.append(spacing[best_spacing])
break
return new_circle_spacing
with this, i obtain a list with the space between each circles that are going to be placed,
from there, i can Call Place_circles() again, and obtain the new stream:
def Place_circles(polyline, circle_space, cs, DoDrawCircle=True, surface=None):
Circle_list = []
curve = []
next_circle_space = None
dist = 0
for c in reversed(range(0, len(polyline))):
curve = []
if type(circle_space) == list:
iter_circle_space = iter(circle_space[c])
next_circle_space = next(iter_circle_space, circle_space[c][-1])
for p in reversed(range(len(polyline[c])-1)):
dist += math.sqrt((polyline[c][p+1][0] - polyline[c][p][0]) ** 2 + (polyline [c][p+1][1] - polyline[c][p][1]) ** 2)
if dist > (circle_space if type(circle_space) == int else next_circle_space):
dist = 0
curve.append(circles.circles(round(polyline[c][p][0]), round(polyline[c][p][1]), cs, DoDrawCircle, surface))
if type(circle_space) == list:
next_circle_space = next(iter_circle_space, circle_space[c][-1])
Circle_list.append(curve)
return Circle_list
the result is a stream with varying space between circles (so accelerating or decelerating), the only issue left to be fixed is pygame not updating the screen with the new set of circle after i call Place_circles(), but that's an issue i'm either going to try to fix myself or ask in another post
the final code for this feature can be found on my repo : https://github.com/Mrcubix/Osu-StreamGenerator/tree/Acceleration_v02
I'm new at Python programming and I'm doing my best to fully understand this code. Here we are printing the path for the First Search Program - Artificial Intelligence for Robotics algorithm. I know how the basic of these lines are working in general, but how they work here in this code. Could I get some clarification for this piece of code below, please?.
This is below the piece of code:
policy=[[' ' for row in range(len(grid[0]))] for col in range(len(grid))]
x=goal[0]
y=goal[1]
policy[x][y]='*'
while x !=init[0] or y !=init[1]:
x2=x-delta[action[x][y]][0]
y2=y-delta[action[x][y]][1]
policy[x2][y2]= delta_name[action[x][y]]
x=x2
y=y2
for i in range(len(policy)):
print(policy[i])
This is the code:
#grid format
# 0 = navigable space
# 1 = occupied space
grid = [[0,0,1,0,0,0],
[0,0,1,0,0,0],
[0,0,0,0,1,0],
[0,0,1,1,1,0],
[0,0,0,0,1,0]]
init = [0,0] #Start location is (0,0) which we put it in open list.
goal = [len(grid)-1,len(grid[0])-1] #Our goal in (4,5) and here are the coordinates of the cell.
#Below the four potential actions to the single field
delta = [[-1 , 0], #up by subtracting one from the first dimention, I mean the demension of (0,0)
[ 0 ,-1], #left
[ 1 , 0], #down
[ 0 , 1]] #right
delta_name = ['^','<','V','>'] #The name of above actions
cost = 1 #Each step costs you one
def search():
#open list elements are of the type [g,x,y]
#To check cells once they expanded and don't expand them again. We defined an array called closed
#and its size as our grid. It has two values 0 & 1. 0 means open and 1 means closed.
closed = [[0 for row in range(len(grid[0]))] for col in range(len(grid))]
action=[[-1 for row in range(len(grid[0]))] for col in range(len(grid))]
#We initialize the starting location as checked
closed[init[0]][init[1]] = 1
# we assigned the cordinates and g value
x = init[0]
y = init[1]
g = 0
#our open list will contain our initial value
open = [[g, x, y]]
found = False #flag that is set when search complete
resign = False #Flag set if we can't find expand
#print('initial open list:')
#for i in range(len(open)):
#print(' ', open[i])
#print('----')
while found is False and resign is False:
#Check if we still have elements in the open list
if len(open) == 0: #If our open list is empty, there is nothing to expand.
resign = True
print('Fail')
print('############# Search terminated without success')
else:
#if there is still elements on our list
#remove node from list
open.sort() #sort elements in an increasing order from the smallest g value up
open.reverse() #reverse the list
next = open.pop() #remove the element with the smallest g value from the list
#print('list item')
#print('next')
#Then we assign the three values to x,y and g. Which is our expantion.
x = next[1]
y = next[2]
g = next[0]
#Check if we are done
if x == goal[0] and y == goal[1]:
found = True
print(next) #The three elements above this "if".
print('############## Search is success')
else:
#expand winning element and add to new open list
for i in range(len(delta)): #going through all our actions the four actions
#We apply the actions to x and y with additional delta to construct x2 and y2
x2 = x + delta[i][0]
y2 = y + delta[i][1]
#if x2 and y2 falls into the grid
if x2 >= 0 and x2 < len(grid) and y2 >=0 and y2 <= len(grid[0])-1:
#if x2 and y2 not checked yet and there is not obstacles
if closed[x2][y2] == 0 and grid[x2][y2] == 0:
g2 = g + cost #we increment the cose
open.append([g2,x2,y2]) #we add them to our open list
#print('append list item')
#print([g2,x2,y2])
#Then we check them to never expand again
closed[x2][y2] = 1
action[x2][y2]=i
policy=[[' ' for row in range(len(grid[0]))] for col in range(len(grid))]
x=goal[0]
y=goal[1]
policy[x][y]='*'
while x !=init[0] or y !=init[1]:
x2=x-delta[action[x][y]][0]
y2=y-delta[action[x][y]][1]
policy[x2][y2]= delta_name[action[x][y]]
x=x2
y=y2
for i in range(len(policy)):
print(policy[i])
search()
I'm trying to implement a filter with Python to sort out the points on a point cloud generated by Agisoft PhotoScan. PhotoScan is a photogrammetry software developed to be user friendly but also allows to use Python commands through an API.
Bellow is my code so far and I'm pretty sure there is better way to write it as I'm missing something. The code runs inside PhotoScan.
Objective:
Selecting and removing 10% of points at a time with error within defined range of 50 to 10. Also removing any points within error range less than 10% of the total, when the initial steps of selecting and removing 10% at a time are done. Immediately after every point removal an optimization procedure should be done. It should stop when no points are selectable or when selectable points counts as less than 1% of the present total points and it is not worth removing them.
Draw it for better understanding:
Actual Code Under Construction (3 updates - see bellow for details):
import PhotoScan as PS
import math
doc = PS.app.document
chunk = doc.chunk
# using float with range and that by setting i = 1 it steps 0.1 at a time
def precrange(a, b, i):
if a < b:
p = 10**i
sr = a*p
er = (b*p) + 1
p = float(p)
for n in range(sr, er):
x = n/p
yield x
else:
p = 10**i
sr = b*p
er = (a*p) + 1
p = float(p)
for n in range(sr, er):
x = n/p
yield x
"""
Determine if x is close to y:
x relates to nselected variable
y to p10 variable
math.isclose() Return True if the values a and b are close to each other and
False otherwise
var is the tolerance here setted as a relative tolerance:
rel_tol is the relative tolerance – it is the maximum allowed difference
between a and b, relative to the larger absolute value of a or b. For example,
to set a tolerance of 5%, pass rel_tol=0.05. The default tolerance is 1e-09,
which assures that the two values are the same within about 9 decimal digits.
rel_tol must be greater than zero.
"""
def test_isclose(x, y, var):
if math.isclose(x, y, rel_tol=var): # if variables are close return True
return True
else:
False
# 1. define filter limits
f_ReconstUncert = precrange(50, 10, 1)
# 2. count initial point number
tiePoints_0 = len(chunk.point_cloud.points) # storing info for later
# 3. call Filter() and init it
f = PS.PointCloud.Filter()
f.init(chunk, criterion=PS.PointCloud.Filter.ReconstructionUncertainty)
a = 0
"""
Way to restart for loop!
should_restart = True
while should_restart:
should_restart = False
for i in xrange(10):
print i
if i == 5:
should_restart = True
break
"""
restartLoop = True
while restartLoop:
restartLoop = False
for count, i in enumerate(f_ReconstUncert): # for each threshold value
# count points for every i
tiePoints = len(chunk.point_cloud.points)
p10 = int(round((10 / 100) * tiePoints, 0)) # 10% of the total
f.selectPoints(i) # selects points
nselected = len([p for p in chunk.point_cloud.points if p.selected])
percent = round(nselected * 100 / tiePoints, 2)
if nselected == 0:
print("For threshold {} there´s no selectable points".format(i))
break
elif test_isclose(nselected, p10, 0.1):
a += 1
print("Threshold found in iteration: ", count)
print("----------------------------------------------")
print("# {} Removing points from cloud ".format(a))
print("----------------------------------------------")
print("# {}. Reconstruction Uncerntainty:"
" {:.2f}".format(a, i))
print("{} - {}"
" ({:.1f} %)\n".format(tiePoints,
nselected, percent))
f.removePoints(i) # removes points
# optimization procedure needed to refine cameras positions
print("--------------Optimizing cameras-------------\n")
chunk.optimizeCameras(fit_f=True, fit_cx=True,
fit_cy=True, fit_b1=False,
fit_b2=False, fit_k1=True,
fit_k2=True, fit_k3=True,
fit_k4=False, fit_p1=True,
fit_p2=True, fit_p3=False,
fit_p4=False, adaptive_fitting=False)
# count again number of points in point cloud
tiePoints = len(chunk.point_cloud.points)
print("= {} remaining points after"
" {} removal".format(tiePoints, a))
# reassigning variable to get new 10% of remaining points
p10 = int(round((10 / 100) * tiePoints, 0))
percent = round(nselected * 100 / tiePoints, 2)
print("----------------------------------------------\n\n")
# restart loop to investigate from range start
restartLoop = True
break
else:
f.resetSelection()
continue # continue to next i
else:
f.resetSelection()
print("for loop didnt work out")
print("{} iterations done!".format(count))
tiePoints = len(chunk.point_cloud.points)
print("Tiepoints 0: ", tiePoints_0)
print("Tiepoints 1: ", tiePoints)
Problems:
A. Currently I'm stuck on an endless processing because of a loop. I know it's about my bad coding. But how do I implement my objective and get away with the infinite loops? ANSWER: Got the code less confusing and updated above.
B. How do I start over (or restart) my search for valid threshold values in the range(50, 20) after finding one of them? ANSWER: Stack Exchange: how to restart a for loop
C. How do I turn the code more pythonic?
IMPORTANT UPDATE 1: altered above
Using a better range with float solution adapted from stackoverflow: how-to-use-a-decimal-range-step-value
# using float with range and that by setting i = 1 it steps 0.1 at a time
def precrange(a, b, i):
if a < b:
p = 10**i
sr = a*p
er = (b*p) + 1
p = float(p)
return map(lambda x: x/p, range(sr, er))
else:
p = 10**i
sr = b*p
er = (a*p) + 1
p = float(p)
return map(lambda x: x/p, range(sr, er))
# some code
f_ReconstUncert = precrange(50, 20, 1)
And also using math.isclose() to determine if selected points are close to the 10% selected points instead of using a manual solution through assigning new variables. This was implemented as follows:
"""
Determine if x is close to y:
x relates to nselected variable
y to p10 variable
math.isclose() Return True if the values a and b are close to each other and
False otherwise
var is the tolerance here setted as a relative tolerance:
rel_tol is the relative tolerance – it is the maximum allowed difference
between a and b, relative to the larger absolute value of a or b. For example,
to set a tolerance of 5%, pass rel_tol=0.05. The default tolerance is 1e-09,
which assures that the two values are the same within about 9 decimal digits.
rel_tol must be greater than zero.
"""
def test_threshold(x, y, var):
if math.isclose(x, y, rel_tol=var): # if variables are close return True
return True
else:
False
# some code
if test_threshold(nselected, p10, 0.1):
# if true then a valid threshold is found
# some code
UPDATE 2: altered on code under construction
Minor fixes and got to restart de for loop from beginning by following guidance from another Stack Exchange post on the subject. Have to improve the range now or alter the isclose() to get more values.
restartLoop = True
while restartLoop:
restartLoop = False
for i in range(0, 10):
if condition:
restartLoop = True
break
UPDATE 3: Code structure to achieve listed objectives:
threshold = range(0, 11, 1)
listx = []
for i in threshold:
listx.append(i)
restart = 0
restartLoop = True
while restartLoop:
restartLoop = False
for idx, i in enumerate(listx):
print("do something as printing i:", i)
if i > 5: # if this condition restart loop
print("found value for condition: ", i)
del listx[idx]
restartLoop = True
print("RESTARTING LOOP\n")
restart += 1
break # break inner while and restart for loop
else:
# continue if the inner loop wasn't broken
continue
else:
continue
print("restart - outer while", restart)
I'm currently doing a project, and in the code I have, I'm trying to get trees .*. and mountains .^. to spawn in groups around the first tree or mountain which is spawned randomly, however, I can't figure out how to get the trees and mountains to spawn in groups around a single randomly generated point. Any help?
grid = []
def draw_board():
row = 0
for i in range(0,625):
if grid[i] == 1:
print("..."),
elif grid[i] == 2:
print("..."),
elif grid[i] == 3:
print(".*."),
elif grid[i] == 4:
print(".^."),
elif grid[i] == 5:
print("[T]"),
else:
print("ERR"),
row = row + 1
if row == 25:
print ("\n")
row = 0
return
There's a number of ways you can do it.
Firstly, you can just simulate the groups directly, i.e. pick a range on the grid and fill it with a specific figure.
def generate_grid(size):
grid = [0] * size
right = 0
while right < size:
left = right
repeat = min(random.randint(1, 5), size - right) # *
right = left + repeat
grid[left:right] = [random.choice(figures)] * repeat
return grid
Note that the group size need not to be uniformly distributed, you can use any convenient distribution, e.g. Poisson.
Secondly, you can use a Markov Chain. In this case group lengths will implicitly follow a Geometric distribution. Here's the code:
def transition_matrix(A):
"""Ensures that each row of transition matrix sums to 1."""
copy = []
for i, row in enumerate(A):
total = sum(row)
copy.append([item / total for item in row])
return copy
def generate_grid(size):
# Transition matrix ``A`` defines the probability of
# changing from figure i to figure j for each pair
# of figures i and j. The grouping effect can be
# obtained by setting diagonal entries A[i][i] to
# larger values.
#
# You need to specify this manually.
A = transition_matrix([[5, 1],
[1, 5]]) # Assuming 2 figures.
grid = [random.choice(figures)]
for i in range(1, size):
current = grid[-1]
next = choice(figures, A[current])
grid.append(next)
return grid
Where the choice function is explained in this StackOverflow answer.