Array not updating values after function call - python

I need the array to have all the possible combinations of the (x,y) coordinates that I am generating. The array still prints as an array of 1s.
import numpy as np
coordinates = np.ones([1000, 2])
def translate (x,y):
dx = 5
dy = 5
return x + dx, y + dy
for i in range(0, 100):
for j in range(0, 100):
(x, y) = translate(i, j)
coordinates[i, j] = translate(x, y)
np.append(coordinates, translate(x, y), axis=None)
print(coordinates)
I expect coordinates array to receive the correct values after the translate function is called and not an array of 1s.

If I understand correctly, you want all possible (x,y) coordinates that can be generated by varying x=0..99 and y=0..99 and then adding some dx and dy to x and y, respectively.
One approach, similar to yours, is to initialize an empty list, and then just append a tuple with the translation function you defined:
coordinates = []
def translate (x,y):
dx = 5
dy = 5
return x + dx, y + dy
for x in range(0, 100):
for y in range(0, 100):
coordinates.append(translate(x,y))
print(coordinates)
However, this could be improved. Realize that you are simply adding dx to every x and dy to every y, so you can achieve the same result with simpler code by removing the translate function:
coordinates = []
dx, dy = 5, 5
for x in range(dx, 100+dx):
for y in range(dy, 100+dy):
coordinates.append((x,y))
print(coordinates)
Which will give you the same correct answer.

Related

Logical indexing python

I am working on improving the speed of logical indexing in Python. So, currently I have to plot some heatmaps, for which I am divinding the inputs data into specified number of x and y bins, and then through the function return_val, I am using logical indexing to compute the mean value in a given bin
This works well when my bin size is small, but when I try to increase the bin size, to let say 100x100, then the program slows down quite a lot
I know that the speed could be increased by using the stats.binned_statistic_2d function in Python. However, I would like to understand how can I optimize my current code in order to make the averaging process go quicker
import numpy as np
arr_len = 932826
x = np.random.uniform(low=0, high=4496, size=arr_len)
y = np.random.uniform(low=-74, high=492, size=arr_len)
z = np.random.uniform(low=-30, high=97, size=arr_len)
# Check points
bin_x = 10
bin_y = 10
x1 = np.linspace(x.min(), x.max(), bin_x)
y1 = np.linspace(y.min(), y.max(), bin_y)
def return_val(x, y, z, x1, y1, i, j):
idx = np.logical_and(np.logical_and(x > x1[i - 1], x < x1[i]), np.logical_and(y > y1[j - 1], y < y1[j]))
if np.count_nonzero(idx) == 0:
return np.nan
else:
return np.mean(z[idx])
z1 = np.zeros((len(x1), len(y1)))
for i in range(1, len(x1)):
for j in range(1, len(y1)):
z1[i - 1, j - 1] = return_val(x, y, z, x1, y1, i, j)
z1 = z1.transpose()
Half the time spent by the code is in implicitly allocating temporary arrays (due to logical_and and comparison operators) and another half the time is spent in the slow nested loops calling a function with the slow CPython interpreter. One way to overcomes these issues is simply to use the Numba's JIT using branchless operations without temporary arrays and using parallelism. Here is an example:
import numpy as np
import numba as nb
arr_len = 932826
x = np.random.uniform(low=0, high=4496, size=arr_len)
y = np.random.uniform(low=-74, high=492, size=arr_len)
z = np.random.uniform(low=-30, high=97, size=arr_len)
# Check points
bin_x = 10
bin_y = 10
x1 = np.linspace(x.min(), x.max(), bin_x)
y1 = np.linspace(y.min(), y.max(), bin_y)
#nb.njit('float64(float64[::1], float64[::1], float64[::1], float64[::1], float64[::1], int32, int32)')
def return_val(x, y, z, x1, y1, i, j):
count = 0
s = 0.0
# Branchless mean
for k in range(len(x)):
valid = (x[k] > x1[i - 1]) & (x[k] < x1[i]) & (y[k] > y1[j - 1]) & (y[k] < y1[j])
s += z[k] * valid
count += valid
if count == 0:
return np.nan
else:
return s / count
#nb.njit('float64[:,:](float64[::1], float64[::1], float64[::1], float64[::1], float64[::1])', parallel=True)
def compute(x, y, z, x1, y1):
z1 = np.zeros((len(x1), len(y1)))
for i in nb.prange(1, len(x1)):
for j in range(1, len(y1)):
z1[i - 1, j - 1] = return_val(x, y, z, x1, y1, i, j)
return z1
z1 = compute(x, y, z, x1, y1)
The above code is 11 times faster on my machine. It can be improved further by working on loops so that the computation can be more cache-friendly.

How to save the minimum path sum in a recursive function?

This is my solution to given a matrix m x n, find the minimum path sum. It works fine however, I'm not sure how to modify it to see the path / save it in some list, how can this be done?
def get_path(matrix, x, y, seen):
if (x, y) in seen:
return seen[x, y]
x_end = len(matrix) - 1
y_end = len(matrix[0]) - 1
current = matrix[x][y]
if x == x_end and y == y_end:
return current
possible_moves = []
if x < len(matrix) - 1:
possible_moves.append([x + 1, y])
if y < len(matrix[0]) - 1:
possible_moves.append([x, y + 1])
results = [
current + get_path(matrix, *possible, seen) for possible in possible_moves
]
current_best = min(results)
seen[x, y] = current_best
return current_best
You don't need to.
After get_path returns, start from 0,0 look for a move where seen[x', y'] = seen[x,y] - matrix[x,y].
If you have equality (both moves work) pick whatever you want (equals paths).
Keep going until you reach the end.

TypeError: can only concatenate list (not "int") to list 4

I'm required to take a Python module for my course and I get this error for my script. It's plotting the trajectory of a projectile and calculating a few other variables. I've typed the script exactly as in the booklet we are given.
Because I am an absolute beginner I can't understand other answers to this error. I would appreciate it an awful lot if someone could give me a quick fix, I don't have time at the moment to learn enough to fix it myself.
Code:
import matplotlib.pyplot as plt
import numpy as np
import math # need math module for trigonometric functions
g = 9.81 #gravitational constant
dt = 1e-3 #integration time step (delta t)
v0 = 40 # initial speed at t = 0
angle = math.pi/4 #math.pi = 3.14, launch angle in radians
time = np.arange(0,10,dt) #time axis
vx0 = math.cos(angle)*v0 # starting velocity along x axis
vy0 = math.sin(angle)*v0 # starting velocity along y axis
xa = vx0*time # compute x coordinates
ya = -0.5*g*time**2 + vy0*time # compute y coordinates
fig1 = plt.figure()
plt.plot(xa, ya) # plot y versus x
plt.xlabel ("x")
plt.ylabel ("y")
plt.ylim(0, 50)
plt.show()
def traj(angle, v0): # function for trajectory
vx0 = math.cos(angle) * v0 # for some launch angle and starting velocity
vy0 = math.sin(angle) * v0 # compute x and y component of starting velocity
x = np.zeros(len(time)) #initialise x and y arrays
y = np.zeros(len(time))
x[0], y[0], 0 #projecitle starts at 0,0
x[1], y[1] = x[0] + vx0 * dt, y[0] + vy0 * dt # second elements of x and
# y are determined by initial
# velocity
i = 1
while y[i] >= 0: # conditional loop continuous until
# projectile hits ground
x[i+1] = (2 * x[i] - x[i - 1]) # numerical integration to find x[i + 1]
y[i+1] = (2 * y[i] - y[i - 1]) - g * dt ** 2 # and y[i + 1]
i = [i + 1] # increment i for next loop
x = x[0:i+1] # truncate x and y arrays
y = y[0:i+1]
return x, y, (dt*i), x[i] # return x, y, flight time, range of projectile
x, y, duration, distance = traj(angle, v0)
print "Distance:" ,distance
print "Duration:" ,duration
n = 5
angles = np.linspace(0, math.pi/2, n)
maxrange = np.zeros(n)
for i in range(n):
x,y, duration, maxrange [i] = traj(angles[i], v0)
angles = angles/2/math.pi*360 #convert rad to degress
print "Optimum angle:", angles[np.where(maxrange==np.max(maxrange))]
The error explicitly:
File "C:/Users/***** at *****", line 52, in traj
x = x[0:i+1] # truncate x and y arrays
TypeError: can only concatenate list (not "int") to list
As is pointed out in the comments, this is the offending line
i = [i + 1] # increment i for next loop
Here, i is not actually being incremented as the comment suggests. When i is 1, it's being set to [1 + 1], which evaluates to [2], the list containing only the number 2. Remove the brackets.

python find vector direction between two 3D points

I'm trying to calculate the direction of a 3D vector starting at point (x, y, z) and ending at point (a, b, c) for the navigation in my spaceship game, but I have been unable to find anything helpful. So far I have tried using two circles, one for figure out x and y and another for z, to figure it out and the code only works if the two vector's distances are very similar.
Here is what I'm using:
def setcourse(self, destination):
x1, y1, z1 = self.coords
x2, y2, z2 = destination
dx = x2 - x1
dy = y2 - y1
dz = z2 - z1
self.heading = math.atan2(dy, dx)
self.heading2 = math.atan2(dz, dy)
self.distance = int(math.sqrt((dx) ** 2 + (dy) ** 2))
self.distance2 = int(math.sqrt((dy) ** 2 + (dz) ** 2))
def move(self):
if self.distance > 0 and self.distance2 > 0:
if self.atwarp == True:
x, y, z = self.coords
x += math.cos(self.heading) * self.speed
y += math.sin(self.heading) * self.speed
z += math.sin(self.heading2) * self.speed
self.coords = (x, y, z)
print(str(self.coords))
self.distance -= self.speed
self.distance2 -= self.speed
elif self.distance <= 0 and self.distance2 <= 0 and self.atwarp == True:
self.atwarp = False
self.speed = 0
print("Reached Destination")
else:
self.atwarp = False
I'm not sure how much of it is a math error and how much is a programming one, but the z winds up way off and I'm not sure how to go about fixing it. No matter what I do the z is always off if its input more than slightly different from the others.
Here is examples starting from (0, 0, 0). I'm trying to get the output to be similar if not the same as the input.
Input: (100, 200, -200)
Vector1 heading in radians: 1.1071487177940904
Vector2 heading: 2.356194490192345
Vector1 distance: 223
Vector2 distance: 282
Output: (99.7286317964909, 199.4572635929818, 157.68481220460077)
The x and y are fine, but the z is off.
Input: (-235, 634, -21)
Vector1 heading in radians: 1.9257588105240444
Vector2 heading: 1.6039072496758664
Vector1 distance: 676
Vector2 distance: 634
Output: (-220.3499891866359, 594.4761410396925, 633.6524941214135)
The z off.
The direction of the movement is the trio dx, dy, dz you calculated. This vector is not pure:
it contains distance and direction. If you want direction alone, you have to normalize
this:
The distance is sqrt(dx^2 + dy^2 + dz^2).
For the normalized direction, you divide each dx, dy, and dz by this number.
If you want to move in that direction, the new position is the old position plus
the the direction vector times the distance you want to travel:
newpos = oldpos + dist * dirvector
I'm not sure what you mean by input: (100, 200, -200) if that is the direction,
your direction vector would be 300 long, and the actual direction vector is
100/300, 200/300, and -200/300 (so 0.333, 0.667 and -0.667)
If you want to travel 500 along that direction, the new position is
0+166.67, 0+333.33, and 0-333.33

Python checking if a point is in sphere with center x, y ,z

I'm trying to check if a point is within a sphere with a center point of (x, y, z) where (x, y, z) is not (0, 0, 0).
This code I'm using to generate the points I want to check:
def generatecoords(self, i):
x, y, z = generatepoint()
if i >= 1:
valid = False
while valid == False:
coords = self.checkpoint(x, y, z)
for b in world.starlist:
if coords == world.starlist[b].coords:
coords = self.checkpoint(x, y, z)
else:
valid = True
else:
coords = self.checkpoint(x, y, z)
return coords
def checkpoint(self, x, y, z):
d = math.sqrt(x * x + y * y + z * z)
while d >= self.radius:
x, y, z = generatepoint()
d = math.sqrt(x * x + y * y + z * z)
coords = (int(x), int(y), int(z))
return coords
def generatepoint():
x, y, z = [int(random.uniform(-self.radius, self.radius)) \
for b in range(3)]
return x, y, z
These function are called in a for loop to generate the points in a dictionary, while also checking the unlikely chance that points aren't placed on top of another(mostly because I can).
I trying to figure out what I need to add to math.sqrt(x * x + y * y + z * z) so that it accounts for a center that isn't (0, 0, 0). I do know of one way to do it, but it would require several lines of code and I'd rather do it in one. I would have asked this in the comments of the answer in another question, but I'm not allowed to comment on answers yet.
The formula is:
A point (x,y,z) is inside the sphere with center (cx,cy,cz) and radius r if
(x - cx)^2 + (y - cy)^2 + (z - cz)^2 < r^2
Here is a very short function that returns True if the point is in the sphere, and False if not.
The inputs are two numpy arrays: point = [x,y,z] and ref = [x,y,z] and the radius should be a float.
import numpy as np
def inSphere(self, point, ref, radius):
# Calculate the difference between the reference and measuring point
diff = np.subtract(point, ref)
# Calculate square length of vector (distance between ref and point)^2
dist = np.sum(np.power(diff, 2))
# If dist is less than radius^2, return True, else return False
return dist < radius ** 2

Categories

Resources