Related
I'm drawing a blank on trying to come up with a simple square grid lookup in python and hope someone can give me some pointers here. Let's say I have a 5x5 grid, starting from the center (3,3), I'd like the lookup to step up the radius outputting the peripheral coordinates like this:
Radius Output
0 [[3,3]]
1 [[2,2], [2,3], [2,4], [3,2], [3,4], [4,2], [4,3], [4,4]]
2 [[1,1], [1,2], [1,3], [1,4], [1,5], [2,1], [2,5], [3,1],
[3,5], [4,1], [4,5], [1,1], [1,2], [1,3], [1,4], [1,5]]
Any pointers will be greatly appreciated!
UPDATE: The code I have at the moment is:
center_coordinate = [3, 3]
completed_locations = [center_coordinate]
radius = 0
max_radius = 3
while radius != max_radius:
x_grid = [x for x in range(center_coordinate[0] - radius, center_coordinate[0] + radius + 1)]
y_grid = [y for y in range(center_coordinate[0] - radius, center_coordinate[0] + radius + 1)]
locations = []
for x in x_grid:
for y in y_grid:
if [x, y] not in completed_locations:
locations.append([x, y])
completed_locations.append([x, y])
radius += 1
print(radius, locations)
While this does do the job, I am looking for a solution that wouldn't require me to cross check each location as it iterates through.. the actual grid size i'll be working against is 750x750 and this particular module will be called on regularly.
Thanks for the pointer #think-maths. I've adapted my code an appreciate the significant boost to performance. I've included both the codes here as reference for anyone doing something similar (like iterating over a game's tile map ;) ).
def adapted_lookup(center_coordinate, max_radius=50):
# ADAPTED FROM think-maths
center_coordinate = [375, 375]
locations_by_radius = []
radius = 0
while radius != max_radius:
x_grid = [x for x in range(center_coordinate[0] - radius, center_coordinate[0] + radius + 1)]
y_grid = [y for y in range(center_coordinate[0] - radius, center_coordinate[0] + radius + 1)]
locations = []
if len(x_grid) > 1:
for x in x_grid:
locations.append([x, y_grid[0]])
if x == x_grid[0] or x == x_grid[-1]:
for y in range(y_grid[1], y_grid[-1]):
locations.append([x, y])
locations.append([x, y_grid[-1]])
else:
locations.append([x_grid[0], y_grid[0]])
locations_by_radius.append([radius, locations])
radius += 1
def original_lookup(center_coordinate, max_radius=50):
# ORIGINAL CODE
locations_by_radius = []
checked = []
radius = 0
while radius != max_radius:
x_grid = [x for x in range(center_coordinate[0] - radius, center_coordinate[0] + radius + 1)]
y_grid = [y for y in range(center_coordinate[0] - radius, center_coordinate[0] + radius + 1)]
locations = []
for x in x_grid:
for y in y_grid:
if [x, y] not in checked:
locations.append([x, y])
checked.append([x, y])
locations_by_radius.append([radius, locations])
radius += 1
Performance according to timeit for a radius of 40 in a 750x750 grid:
Original Lookup Time: 14.5097
Adapted Lookup Time: 0.0020
For such kind of problem where you traverse through grids to form circle then Midpoint circle algorithm is a possibility
For example to demonstrate you can use something like this according to your need to implement your requirement
def midPointCircleDraw(x_centre, y_centre, r):
x = r
y = 0
print("(", x + x_centre, ", ",
y + y_centre, ")",
sep = "", end = "")
if (r > 0) :
print("(", x + x_centre, ", ",
-y + y_centre, ")",
sep = "", end = "")
print("(", y + x_centre, ", ",
x + y_centre, ")",
sep = "", end = "")
print("(", -y + x_centre, ", ",
x + y_centre, ")", sep = "")
P = 1 - r
while x > y:
y += 1
if P <= 0:
P = P + 2 * y + 1
else:
x -= 1
P = P + 2 * y - 2 * x + 1
if (x < y):
break
print("(", x + x_centre, ", ", y + y_centre,
")", sep = "", end = "")
print("(", -x + x_centre, ", ", y + y_centre,
")", sep = "", end = "")
print("(", x + x_centre, ", ", -y + y_centre,
")", sep = "", end = "")
print("(", -x + x_centre, ", ", -y + y_centre,
")", sep = "")
if x != y:
print("(", y + x_centre, ", ", x + y_centre,
")", sep = "", end = "")
print("(", -y + x_centre, ", ", x + y_centre,
")", sep = "", end = "")
print("(", y + x_centre, ", ", -x + y_centre,
")", sep = "", end = "")
print("(", -y + x_centre, ", ", -x + y_centre,
")", sep = "")
I need to calculate the number of paths from top left to right bottom where a valid path is path that crosses all the squares in the grid (and exactly once for every square)
I'm using the backtracking technique. Unfortunately, count is 0 in the end of the calculation. Printing t, I see that it never gets to n-1.
What's wrong with my algorithm?
n = 4
count = 0
m = [[False for x in range(n)] for y in range(n)]
def num_of_paths(m, x, y, t):
print(t)
global count
# check if we reached target
if x == (n - 1) and y == (n - 1):
if t < (n * n):
# not on time, prune the tree here
return
elif t == n * n:
# completed a full path in the grid and on time
count += 1
if t > n * n:
return
# Right
if x + 1 < n and m[x + 1][y] == False:
m[x + 1][y] = True
num_of_paths(m, x + 1, y, t + 1)
m[x + 1][y] = False
# Left
if x - 1 > 0 and m[x - 1][y] == False:
m[x - 1][y] = True
num_of_paths(m, x - 1, y, t + 1)
m[x - 1][y] = False
# Down
if y + 1 < n and m[x][y + 1] == False:
m[x][y + 1] = True
num_of_paths(m, x, y + 1, t + 1)
m[x][y + 1] = False
# Up
if y - 1 > 0 and m[x][y - 1] == False:
m[x][y - 1] = True
num_of_paths(m, x, y - 1, t + 1)
m[x][y - 1] = False
num_of_paths(m, 0, 0, 0)
print(count)
There are the following issues:
The starting cell is not marked with m[0][0] = True, so after going right, the algorithm will go left again, and actually visit that cell twice. To resolve this, you can move the code for managing the m values away from where you have it now (4 times) and apply it to the current cell (once). This includes the if m[..][..] check, and the assignments of True and False.
The if conditions that relate to the left and up directions should compare the coordinate with >= 0, not with > 0: a zero value for a coordinate is still within range.
t should start with 1, since you compare its value with n * n. Or else you should compare with n * n - 1. In my correction below I will start with t = 1.
Not a real problem, but after doing count += 1 it would make sense to immediately return, since there is no possibility anymore to extend the path further.
Some other remarks:
When n is even, there is no valid path, so even when corrected, the function is bound to return 0 in that case
The number of paths this algorithm visits is exponential, O(2n²). For n > 6, don't wait for it...
Here is a corrected version of your code. Comments should clarify what was changed and why:
n = 5
count = 0
m = [[False for x in range(n)] for y in range(n)]
def num_of_paths(m, x, y, t):
global count
# Moved the "visited" check to here. No need to add `== True`.
if m[x][y]:
return
if x == (n - 1) and y == (n - 1):
if t < (n * n):
return
else: # Removed the unnecessary condition here
count += 1
# Added a return here
return
# Removed an if-block of which the condition could never be true
# Moved the "visited" marking to here:
m[x][y] = True
if x + 1 < n:
num_of_paths(m, x + 1, y, t + 1)
# Corrected "> 0" to ">= 0"
if x - 1 >= 0:
num_of_paths(m, x - 1, y, t + 1)
if y + 1 < n:
num_of_paths(m, x, y + 1, t + 1)
# Corrected "> 0" to ">= 0"
if y - 1 >= 0:
num_of_paths(m, x, y - 1, t + 1)
# Moved the "visited" unmarking to here:
m[x][y] = False
# Corrected the last argument
num_of_paths(m, 0, 0, 1)
print(count)
this code is working
n = 3
count=0
m = [[False for x in range(n)] for y in range(n)]
def num_of_paths(m,x,y):
# setting (x,y) position in m = True as we have crossed this square now
m[y][x]=True
global count
# check if we reached target
if x == (n - 1) and y == (n - 1):
# check if we haven't missed any square
for i in m:
if False in i:
m[y][x]=False
return
# increment count if we visited all squares
count+=1
m[y][x]=False
return
# setting up legel directions in which current point(x,y) should head next
dir={'up','down','left','right'}
if x==0:
dir-={'left'}
if x==n-1:
dir-={'right'}
if y==0:
dir-={'up'}
if y==n-1:
dir-={'down'}
# now we have all legal directions that (x,y) could go to
# now iterate over all possible directions of (x,y)
for i in dir:
if i=='left': # left means (x,y) will change to (x-1,y) i.e. change is (-1,0)
if m[y][x-1]==False: # it means left of (x,y) havent yet crossed i.e. it is legel to visit now
num_of_paths(m,x-1,y)
# similiarly for other possible directions
if i=='right':
if m[y][x+1]==False:
num_of_paths(m,x+1,y)
if i=='up':
if m[y-1][x]==False:
num_of_paths(m,x,y-1)
if i=='down':
if m[y+1][x]==False:
num_of_paths(m,x,y+1)
num_of_paths(m,0,0)
print(count)
let me know if there is some issue
I was trying to do a program which can take square matrix of any size and find two any square submatrixes(they shouldn't overlap), whose qualities are the closest. So every elementary square in matrix has a quality(any number). The problem is algorithm is too slow with processing matrixes 100*100 containing big negative numbers(-10^8).
from collections import defaultdict
from math import fsum
from itertools import islice, count
def matrix():
matritsa = list()
koord = list()
ssum = 0
diff = defaultdict(list)
size = int(input()) #size of the matrix
for line in range(size):
matritsa += list(map(int,input().split())) #filling the matrix
Q1,Q2 = map(int,input().split()) #quality range
for i in range(len(matritsa)):
element = matritsa[i]
if Q1 <= element and element <= Q2: #checking if an element is in range
koord.append([element, i//size, i%size, 1]) #coordinates of 1*1 elements
for razmer in range(2,size): #taking squares of 2+ size
#print("Razmer: ",razmer)
for a in range(len(matritsa)):
(x,y) = a//size,a%size #coordinates of the left top square
if y + razmer > size:
continue
ssum = 0
for b in range(x,x+razmer):
ssum += sum(matritsa[b*size+y:b*size+(y+razmer)])
if Q1 <= ssum and ssum <= Q2: #checking if it is in quality range
koord.append([ssum,x,y,razmer])
#print(koord)
#print("Coordinate: {0},{1}; ssum: {2}".format(x,y,ssum))
if x + razmer == size and y + razmer == size:
#print("Final: {0},{1}".format(x,y))
break
g = 0
temp = len(koord)
while g != temp:
(value1,x1,y1,a) = koord[g]
for i in range(g,temp - 1):
(value2,x2,y2,b) = koord[i+1]
if y1 >= y2 + b or y2 >= y1 + a:
diff[abs(value1 - value2)].append([value1,value2])
if x1 >= x2 + b or x2 >= x1 + a:
diff[abs(value1 - value2)].append([value1,value2])
g += 1
minimum = min(diff.keys())
if minimum == 0:
print(*max(diff[minimum]))
elif len(diff[minimum]) > 1:
maximum = sum(diff[minimum][0])
result = diff[minimum][0]
for pair in diff[minimum]:
if sum(pair) > maximum:
maximum = sum(pair)
result = pair
The problem is in this part
g = 0
temp = len(koord)
print(temp)
while g != temp:
(value1,x1,y1,a) = koord[g]
for i in range(g,temp - 1):
(value2,x2,y2,b) = koord[i+1]
if y1 >= y2 + b or y2 >= y1 + a:
diff[abs(value1 - value2)].append([value1,value2])
if x1 >= x2 + b or x2 >= x1 + a:
diff[abs(value1 - value2)].append([value1,value2])
g += 1
For a school assignment I need to print a smiley using a hollow circle.
def circle(i):
i += 1
from math import sqrt
result = ""
midden = i / 2.0
for a in range(i):
for b in range(i):
c = sqrt((midden - a)**2 + (midden - b)**2)
if midden > c:
result += "#"
else:
result += " "
result += "\n"
print(result)
circle(11)
The code above is what I have used to print a filled circle but i cannot for the life of me figure out how to make the circle hollow
Here is code that will first create a matrix with spaces, and walks along 1/8th of the circle, placing '#' characters. The 7 mirroring positions can be set at the same time, filling the complete circle. Finally the matrix is converted to a string which is returned.
from math import sqrt
def circle(radius):
pixels = [[' ' for x in range(2*radius+1)] for y in range(2*radius+1)]
y = radius
x = 0
max = (radius + 0.5)**2
while x <= y:
pixels[radius+y][radius+x] = '#'
pixels[radius+y][radius-x] = '#'
pixels[radius-y][radius+x] = '#'
pixels[radius-y][radius-x] = '#'
pixels[radius+x][radius+y] = '#'
pixels[radius+x][radius-y] = '#'
pixels[radius-x][radius+y] = '#'
pixels[radius-x][radius-y] = '#'
x += 1
if x*x + y*y >= max:
y -= 1
return '\n'.join([''.join([v for v in row]) for row in pixels])
print(circle(11))
I need help in the following: I have a data file (columns separated by "\t" tabular) like this data.dat
# y1 y2 y3 y4
17.1685 21.6875 20.2393 26.3158
These are x values of 4 points for a linear fit. The four y values are constant: 0, 200, 400, 600.
I can create a linear fit of the point pairs (x,y): (x1,y1)=(17.1685,0), (x2,y2)=(21.6875,200), (x3,y3)=(20.2393,400), (x4,y4)=(26.3158,600).
Now I would like to make a linear fit on three of these point paris, (x1,y1), (x2,y2), (x3,y3) and (x2,y2), (x3,y3), (x4,y4) and (x1,y1), (x3,y3), (x4,y4) and (x1,y1), (x2,y2), (x4,y4).
If I have these three of points with a linear fit I would like to know the value of the x value of the extrapolated point being out of these three fitted points.
I have so far this awk code:
#!/usr/bin/awk -f
BEGIN{
z[1] = 0;
z[2] = 200;
z[3] = 400;
z[4] = 600;
}
{
split($0,str,"\t");
n = 0.0;
for(i=1; i<=NF; i++)
{
centr[i] = str[i];
n += 1.0;
# printf("%d\t%f\t%.1f\t",i,centr[i],z[i]);
}
# print "";
if (n > 2)
{
lsq(n,z,centr);
}
}
function lsq(n,x,y)
{
sx = 0.0
sy = 0.0
sxx = 0.0
syy = 0.0
sxy = 0.0
eps = 0.0
for (i=1;i<=n;i++)
{
sx += x[i]
sy += y[i]
sxx += x[i]*x[i]
sxy += x[i]*y[i]
syy += y[i]*y[i]
}
if ( (n==0) || ((n*sxx-sx*sx)==0) )
{
next;
}
# print "number of data points = " n;
a = (sxx*sy-sxy*sx)/(n*sxx-sx*sx)
b = (n*sxy-sx*sy)/(n*sxx-sx*sx)
for(i=1;i<=n;i++)
{
ycalc[i] = a+b*x[i]
dy[i] = y[i]-ycalc[i]
eps += dy[i]*dy[i]
}
print "# Intercept =\t"a"
print "# Slope =\t"b"
for (i=1;i<=n;i++)
{
printf("%8g %8g %8g \n",x[i],y[i],ycalc[i])
}
} # function lsq()
So,
If we extrapolate to the place of 4th
0 17.1685 <--(x1,y1)
200 21.6875 <--(x2,y2)
400 20.2393 <--(x3,y3)
600 22.7692 <<< (x4 = 600,y1 = 22.7692)
If we extrapolate to the place of 3th
0 17.1685 <--(x1,y1)
200 21.6875 <--(x2,y2)
400 23.6867 <<< (x3 = 400,y3 = 23.6867)
600 26.3158 <--(x4,y4)
0 17.1685
200 19.35266 <<<
400 20.2393
600 26.3158
0 18.1192 <<<
200 21.6875
400 20.2393
600 26.3158
My current output is the following:
$> ./prog.awk data.dat
# Intercept = 17.4537
# Slope = 0.0129968
0 17.1685 17.4537
200 21.6875 20.0531
400 20.2393 22.6525
600 26.3158 25.2518
Assuming the core calculation in the lsq function is OK (it looks about right, but I haven't scrutinized it), then that gives you the slope and intercept for the least sum of squares line of best fit for the input data set (parameters x, y, n). I'm not sure I understand the tail end of the function.
For your 'take three points and calculate the fourth' problem, the simplest way is to generate the 4 subsets (logically, by deleting one point from the set of four on each of four calls), and redo the calculation.
You need to call another function that takes the line data (slope, intercept) from lsq and interpolates (extrapolates) the value at another y value. That's a straight-forward calculation (x = m * y + c), but you need to determine which y value is missing from the set of 3 you pass in.
You could 'optimize' (meaning 'complicate') this scheme by dropping one value at a time from the 'sums of squares' and 'sums' and 'sum of products' values, recalculating the slope, intercept, and then calculating the missing point again.
(I'll also observe that normally it would be the x-coordinates with the fixed values 0, 200, 400, 600 and the y-coordinates would be the values read. However, that's just a matter of orientation, so it is not crucial.)
Here's at least plausibly working code. Since awk automatically splits on white space, there's no need for you to split on tabs specifically; the read loop takes this into account.
The code needs serious refactoring; there is a ton of repetition in it - however, I also have a job that I'm supposed to do.
#!/usr/bin/awk -f
BEGIN{
z[1] = 0;
z[2] = 200;
z[3] = 400;
z[4] = 600;
}
{
for (i = 1; i <= NF; i++)
{
centr[i] = $i
}
if (NF > 2)
{
lsq(NF, z, centr);
}
}
function lsq(n, x, y)
{
if (n == 0) return
sx = 0.0
sy = 0.0
sxx = 0.0
syy = 0.0
sxy = 0.0
for (i = 1; i <= n; i++)
{
print "x[" i "] = " x[i] ", y[" i "] = " y[i]
sx += x[i]
sy += y[i]
sxx += x[i]*x[i]
sxy += x[i]*y[i]
syy += y[i]*y[i]
}
if ((n*sxx - sx*sx) == 0) return
# print "number of data points = " n;
a = (sxx*sy-sxy*sx)/(n*sxx-sx*sx)
b = (n*sxy-sx*sy)/(n*sxx-sx*sx)
for (i = 1; i <= n; i++)
{
ycalc[i] = a+b*x[i]
}
print "# Intercept = " a
print "# Slope = " b
print "Line: x = " a " + " b " * y"
for (i = 1; i <= n; i++)
{
printf("x = %8g, yo = %8g, yc = %8g\n", x[i], y[i], ycalc[i])
}
print ""
print "Different subsets\n"
for (drop = 1; drop <= n; drop++)
{
print "Subset " drop
sx = sy = sxx = sxy = syy = 0
j = 1
for (i = 1; i <= n; i++)
{
if (i == drop) continue
print "x[" j "] = " x[i] ", y[" j "] = " y[i]
sx += x[i]
sy += y[i]
sxx += x[i]*x[i]
sxy += x[i]*y[i]
syy += y[i]*y[i]
j++
}
if (((n-1)*sxx - sx*sx) == 0) continue
a = (sxx*sy-sxy*sx)/((n-1)*sxx-sx*sx)
b = ((n-1)*sxy-sx*sy)/((n-1)*sxx-sx*sx)
print "Line: x = " a " + " b " * y"
xt = x[drop]
yt = a + b * xt;
print "Interpolate: x = " xt ", y = " yt
}
}
Since awk doesn't provide an easy way to pass back multiple values from a function, nor does it provide structures other than arrays (sometimes associative), it is not perhaps the best language for this task. On the other hand, it can be made to do the job. You might be able to bundle the Least Squares calculation in a function that returns an array containing the slope and intercept, and then use that. Your turn to explore options.
Given the script lsq.awk and the input file lsq.data shown, I get the output shown:
$ cat lsq.data
17.1685 21.6875 20.2393 26.3158
$ awk -f lsq.awk lsq.data
x[1] = 0, y[1] = 17.1685
x[2] = 200, y[2] = 21.6875
x[3] = 400, y[3] = 20.2393
x[4] = 600, y[4] = 26.3158
# Intercept = 17.4537
# Slope = 0.0129968
Line: x = 17.4537 + 0.0129968 * y
x = 0, yo = 17.1685, yc = 17.4537
x = 200, yo = 21.6875, yc = 20.0531
x = 400, yo = 20.2393, yc = 22.6525
x = 600, yo = 26.3158, yc = 25.2518
Different subsets
Subset 1
x[1] = 200, y[1] = 21.6875
x[2] = 400, y[2] = 20.2393
x[3] = 600, y[3] = 26.3158
Line: x = 18.1192 + 0.0115708 * y
Interpolate: x = 0, y = 18.1192
Subset 2
x[1] = 0, y[1] = 17.1685
x[2] = 400, y[2] = 20.2393
x[3] = 600, y[3] = 26.3158
Line: x = 16.5198 + 0.0141643 * y
Interpolate: x = 200, y = 19.3526
Subset 3
x[1] = 0, y[1] = 17.1685
x[2] = 200, y[2] = 21.6875
x[3] = 600, y[3] = 26.3158
Line: x = 17.7985 + 0.0147205 * y
Interpolate: x = 400, y = 23.6867
Subset 4
x[1] = 0, y[1] = 17.1685
x[2] = 200, y[2] = 21.6875
x[3] = 400, y[3] = 20.2393
Line: x = 18.163 + 0.007677 * y
Interpolate: x = 600, y = 22.7692
$
Edit: In the previous version of the answer, the subsets were multiplying by n instead of (n-1). The values in the revised output seem to agree with what you expect. The residual issues are presentational, not computational.